CF1408I. Bitwise Magic

题目描述

题解

首先有一个显然的重要结论:一个数减k后只会影响到最后log k位

所以先把异或和求出来,问题变成给出一些集合\((0,x \;xor \;(x-1),x \;xor \;(x-2),...x \;xor \;(x-k))\),在里面选择一些数异或起来求方案

这样的组数很少,因为只和最后log k位以及第(log k)位后第一个1的位置有关(最后log k位加上以log k开始的一段1),所以是c^2的,丢到数组h[i,j]里表示第i位是第一个1后log k位为j

(以下均把k换成c)

可以预处理一个数组g[i,j,k,0/1]表示后面的第一个1在第i位,选了j个,最后log c位异或为k,第i位是否被异或

这个可以压成一个二项式\(x^iy^j\)表示个数和异或值,0/1也压进去

算方案转EGF,FWT后快速幂,这部分时间是O(c^6)(枚举h[i,j]2个c快速幂1个c乘法3个c)

根据0/1的奇偶可以搞出g[i,0/1]表示第一个1在i,选完后log k~i是否反转

之后dp合并,设f[s]表示当前合并的位,每次考虑下一位转移即可,s的范围是2^c/c,里面的乘法是c^3,所以时间是O(2^c*c^2),已经可以过了

后一部分的常数非常大,所以可以ln后变成加法,可以少掉一个c

如果时间写错了变成2^c*c^3可能会过不了,尽管在本机只跑了1.9s

code

没写lnexp

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%998244353
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define mod 998244353
#define Mod 998244351
#define two 499122177
#define ll long long
//#define file
using namespace std;

ll h[17][17],ans[65536],N,jc[17],Jc[17];
int a[65536],p[17],n,K,L,c,i,j,k,l,Sum,x;

struct type{ll a[32];void clear() {memset(a,0,sizeof(a));}};
struct Type{type a[17]; void clear() {int i; fo(i,0,16) a[i].clear();}} g[17][2],G[17],f[4096],F[4096],s,I;
void turn(type &a,int tp)
{
	int i,j,k,l,S=p[L+1],s1=2,s2=1;
	ll u,v;
	
	fo(i,1,L+1)
	{
		S>>=1;
		fo(j,0,S-1)
		{
			fo(k,0,s2-1)
			{
				u=a.a[j*s1+k],v=a.a[j*s1+k+s2];
				a.a[j*s1+k]=(u+v)%mod;
				a.a[j*s1+k+s2]=(u-v)%mod;
				if (tp==-1) a.a[j*s1+k]=a.a[j*s1+k]*two%mod,a.a[j*s1+k+s2]=a.a[j*s1+k+s2]*two%mod;
			}
		}
		s1<<=1,s2<<=1;
	}
}
type operator +(type a,type b)
{
	static type c;
	int i;
	fo(i,0,p[L+1]-1) c.a[i]=(a.a[i]+b.a[i])%mod;
	return c;
}
type operator *(type a,type b)
{
	static type c;
	int i;
	fo(i,0,p[L+1]-1) c.a[i]=(a.a[i]*b.a[i])%mod;
	return c;
}

Type operator *(Type a,Type b)
{
	static Type c;
	int i,j,k,l;
	c.clear();
	
	fo(i,0,K)
	{
		fo(j,0,i)
		c.a[i]=c.a[i]+(a.a[j]*b.a[i-j]);
	}
	return c;
}
void Turn(Type &a,int tp)
{
	int i;
	fo(i,0,K)
	turn(a.a[i],tp);
}
void TurnEGF(Type &a)
{
	int i,j;
	fo(i,0,K)
	{
		fo(j,0,p[L+1]-1)
		a.a[i].a[j]=a.a[i].a[j]*Jc[i]%mod;
	}
}

ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
Type Qpower(Type a,int b) {static Type ans;ans=I;while (b) {if (b&1) ans=ans*a;a=a*a;b>>=1;} return ans;}
void init()
{
	int i;
	p[0]=jc[0]=1;
	fo(i,1,16) p[i]=p[i-1]*2,jc[i]=jc[i-1]*i%mod;
	Jc[16]=qpower(jc[16],Mod);
	fd(i,15,0) Jc[i]=Jc[i+1]*(i+1)%mod;
}

void dp()
{
	int I,i,j,k,l,x,S=1;
	
	f[0]=g[c][0];
	fd(I,c-1,L)
	{
		fo(i,0,S-1)
		{
			l=i&1;
			F[i*2+l]=f[i]*g[I][0];
			F[i*2+(!l)]=f[i]*g[I][1];
		}
		fo(i,0,S*2-1) f[i]=F[i],F[i].clear();
		S<<=1;
	}
	
	fo(x,0,p[c-L]-1)
	{
		Turn(f[x],-1);
		fo(k,0,p[L]-1)
		add(ans[k+x*p[L]],f[x].a[K].a[k]);
	}
}

int main()
{
	#ifdef file
	freopen("CF1408I.in","r",stdin);
//	freopen("CF1408I.out","w",stdout);
	#endif
	
	init();
	scanf("%d%d%d",&n,&K,&c);
	
	L=ceil(log2(K));
	fo(i,1,n)
	{
		scanf("%d",&x),Sum^=x;
		
		fo(l,L,c-1)
		if (x&p[l])
		break;
		
		k=x&(p[L]-1);
		++h[l][k];
	}
	
	I.a[0].a[0]=1,Turn(I,1);
	fo(i,L,c) G[i]=I;
	fo(i,L,c)
	{
		fo(j,0,p[L]-1)
		if (h[i][j])
		{
			s.clear();
			fo(k,0,min(j,K))
			++s.a[k].a[j^(j-k)];
			if (j<K)
			{
				fo(k,j+1,K)
				++s.a[k].a[j^(p[L]+j-k)^p[L]];
			}
			TurnEGF(s),Turn(s,1);
			G[i]=G[i]*Qpower(s,h[i][j]);
		}
	}
	fo(i,L,c)
	{
		Turn(G[i],-1);
		fo(k,0,K)
		{
			fo(l,0,p[L]-1)
			{
				add(g[i][0].a[k].a[l],G[i].a[k].a[l]);
				add(g[i][1].a[k].a[l],G[i].a[k].a[l^p[L]]);
			}
		}
		Turn(g[i][0],1),Turn(g[i][1],1);
	}
	dp();
	fo(i,0,p[c]-1) ans[i]=(ans[i]+mod)%mod*jc[K]%mod;
	
	N=qpower(qpower(n,K),Mod);
	fo(i,0,p[c]-1)
	printf("%lld ",ans[i^Sum]*N%mod);
	printf("\n");
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-10-11 21:03  gmh77  阅读(117)  评论(0编辑  收藏  举报