AGC 043C

手玩一下二维的情况发现很像mex,冷静分析一下这个过程,我们将 (0) 设置为要选择的点,那么贪心即为观察后继节点有没有 (0),没有则是 (0),有的话就是 (1)

那么显然可以发现这玩意本质上就是一个博弈,多维的情况就是单维的情况的并,并且这个博弈可以用 ( ext{sg函数}) 表示。

那么暴力算 (sg) 函数,( ext{FWT}) 合并一下即可。

复杂度 (nlog n)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
const int inv2 = (mod+1)>>1;
/* math */
const int N = 1e5+5;
int a[1<<19],b[1<<19],c[1<<19],d[1<<19];
inline void fwt(int *f,int n,int type){
	for(int step=1;step<n;step<<=1){
		for(int i=0;i<n;i+=step<<1){
			for(int j=0;j<step;j++){
				int x=f[i+j], y=f[i+j+step];
				f[i+j] = add(x,y);
				f[i+j+step] = sub(x,y);
				if(type==0){
					f[i+j] = mul(f[i+j], inv2);
					f[i+j+step] = mul(f[i+j+step], inv2);
				}
			}
		}
	}
}
int n,buc[N],sg[N];
vector<int> s[N];
inline void calc(int n,int *q){
	int m;cin >> m;for(int i=1;i<=n;i++)s[i].clear();
	for(int i=1;i<=m;i++){
		int u,v;scanf("%d%d",&u,&v);
		s[min(u,v)].push_back(max(u,v));
	}
	for(int i=n;i;i--){
		sg[i]=0;
		for(size_t j=0;j<s[i].size();j++){
			int v=s[i][j];
			buc[sg[v]]++;
		}
		while(buc[sg[i]])sg[i]++;
		for(size_t j=0;j<s[i].size();j++){
			int v=s[i][j];
			buc[sg[v]]--;
		}
		q[sg[i]]=add(q[sg[i]], qpow(10,18*i));
	}
}

int main()
{
	cin >> n;
	calc(n,a),calc(n,b),calc(n,c);
	fwt(a,1<<19,1);
	fwt(b,1<<19,1);
	fwt(c,1<<19,1);
	for(int i=0;i<1<<19;i++){
		d[i]=mul(a[i],mul(b[i],c[i]));
	}
	fwt(d,1<<19,0);
	cout << d[0] << endl;
}
原文地址:https://www.cnblogs.com/weiyanpeng/p/12566797.html