码迷,mamicode.com
首页 > 其他好文 > 详细

AGC 043 C,D 题解

时间:2021-05-24 15:26:40      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:fir   fast   now()   als   merge   max   long   cpp   stdout   

AGC 043 C,D 题解

C - Giant Graph

首先可以理解成一个\(N\times N\times N\)的立方体从\((N,N,N)\)开始按照\(x+y+z\)降序贪心添加。

一个点不被选当且仅当按照\(x,y,z\)某一个方向可以到达一个选择的。

直接用\(SG\)函数即可。

由于\(SG\)的值域是\(O(\sqrt N)\)的,所以可以暴力卷积,也可以用\(O(\sqrt N\log\sqrt N)\)的FWT。

时间复杂度\(O(N)\)

/*
{
######################
#       Author       #
#        Gary        #
#        2021        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<‘0‘||ch>‘9‘){
//        ch=getchar();
//    }
//    while(ch>=‘0‘&&ch<=‘9‘){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/

const int MAXN=1e5+233;
int n;
int sg1[MAXN<<1],sg2[MAXN<<1],sg3[MAXN<<1];
int a1[MAXN<<1],a2[MAXN<<1],a3[MAXN<<1];
const int MOD=998244353;
int tmp[1<<17];
const int iv2=(MOD+1)/2;
void FMT(int * a,int x){
	for(int k=1;k<n;k<<=1){
		for(int j=0;j<n;j+=(k<<1)){
			rep(i,k){
				if(x==1) (tmp[i+j]=(a[i+j]+a[i+j+k])%MOD,tmp[i+j+k]=(MOD+a[i+j]-a[i+j+k])%MOD);
				else (tmp[i+j]=1ll*(a[i+j]+a[i+j+k])*iv2%MOD,tmp[i+j+k]=1ll*(MOD+a[i+j]-a[i+j+k])*iv2%MOD);
			}
		}
		rep(i,n) a[i]=tmp[i];
	}
}
vector<int> g[MAXN];
namespace GRAPH{
	void read(){
		int m;
		scanf("%d",&m);
		rb(i,1,m){
			int u,v;
			scanf("%d%d",&u,&v);
			if(v<u) swap(u,v);
			g[u].PB(v);
		}
	}
	int Mex(vector<int> v){
		sort(ALL(v));
		v.erase(unique(ALL(v)),v.end());
		v.PB(1000000000);
		rep(i,v.size()) if(v[i]!=i) return i;
		return 0;
	}
	vector<int> gao(){
		vector<int> sg(n+1,0);
		rl(i,n,1){
			vector<int> v;
			for(auto it:g[i]) v.PB(sg[it]);
			sg[i]=Mex(v);
		}
		return sg;
	}
	void clear(){
		rb(i,1,n) g[i].clear();
	}
}
int main(){
	scanf("%d",&n);
	GRAPH::read();
	vector<int> tmp=GRAPH::gao();
	rb(i,1,n) sg1[i]=tmp[i];
	GRAPH::clear();
	
	GRAPH::read();
	tmp=GRAPH::gao();
	rb(i,1,n) sg2[i]=tmp[i];
	GRAPH::clear();
	
	GRAPH::read();
	tmp=GRAPH::gao();
	rb(i,1,n) sg3[i]=tmp[i];
	GRAPH::clear();
	
	int ttmp=1;
	while(ttmp<n) ttmp<<=1;
	int _1018=1;
	rb(i,1,18) _1018=10ll*_1018%MOD;
	int T=1;
	rb(i,1,n) T=1ll*T*_1018%MOD,(a1[sg1[i]]+=T)%=MOD;
	T=1;
	rb(i,1,n) T=1ll*T*_1018%MOD,(a2[sg2[i]]+=T)%=MOD;
	T=1;
	rb(i,1,n) T=1ll*T*_1018%MOD,(a3[sg3[i]]+=T)%=MOD;
	n=ttmp;
	FMT(a1,1);
	FMT(a2,1);
	FMT(a3,1);
	rep(i,n) a1[i]=1ll*a1[i]*a2[i]%MOD*a3[i]%MOD;
	FMT(a1,-1);
	printf("%d\n",a1[0]);
	return 0;
}

D - Merge Triplets

如果一个元素不是前缀最大值则一定和前一个元素属于同一堆。

这样就有长度为\(1,2,3\) 的段。

然后将\(1,2\)两两匹配。

剩下只需要有\(3\)的倍数个\(1\)即可。

\(dp[i][j][k]\)表示考虑了前\(i\)个,有\(j\)个1段,\(k\) 个2 段的方案数。

可以发现\(j,k\)之中必有一个\(0\)

所以状态时\(O(N^2)\)的,转移直接枚举下一段长度即可。

/*
{
######################
#       Author       #
#        Gary        #
#        2021        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<‘0‘||ch>‘9‘){
//        ch=getchar();
//    }
//    while(ch>=‘0‘&&ch<=‘9‘){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=6002;
int MOD,n,dp[MAXN][MAXN<<1];
int T(int i,int k){
	if(k==1) return 1;
	if(k==2) return i+1;
	return 1ll*(i+1)*(i+2)%MOD;
}
int main(){
	scanf("%d%d",&n,&MOD);
	n*=3;
	dp[0][MAXN]=1;
	rb(i,0,n-1){
		rb(j,-n,n)
			if(dp[i][j+MAXN])
				rb(k,1,min(3,n-i)){
					if(k==3){
						(dp[i+3][j+MAXN]+=1ll*dp[i][j+MAXN]*T(i,k)%MOD)%=MOD;
					}
					if(k==2){
						(dp[i+2][j-1+MAXN]+=1ll*dp[i][j+MAXN]*T(i,k)%MOD)%=MOD;
					}
					if(k==1){
						(dp[i+1][j+1+MAXN]+=1ll*dp[i][j+MAXN]*T(i,k)%MOD)%=MOD;
					}
				}
	}
	int rest=0;
	rb(i,0,n) if(i%3==0) (rest+=dp[n][i+MAXN])%=MOD; 
	printf("%d\n",rest);
	return 0;
}

AGC 043 C,D 题解

标签:fir   fast   now()   als   merge   max   long   cpp   stdout   

原文地址:https://www.cnblogs.com/gary-2005/p/14782368.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!