cf453D Little Pony and Elements of Harmony FWT+快速幂

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/87925783

Description


太长自己看系列。。

Solution


记c[i]为i二进制下1的数量, d [ i ] = b [ c [ i ] ] d[i]=b[c[i]] ,那么柿子就是 e [ i ] = x e [ x ] d [ i x ] e'[i]=\sum\limits_{x}e[x]*d[i\oplus x]
然后就是非常套路的换下标了, ( i x ) x = i (i\oplus x)\oplus x=i
于是 e [ i ] = x y = i e [ x ] d [ y ] e'[i]=\sum\limits_{x\oplus y=i}e[x]*d[y] ,由于每一次卷上的d都是不变的,因此可以快速幂预处理

还有一个问题是膜数不一定存在逆元,注意到FWT的写法是酱的

void FWT(LL *a,int n,int f) {
	for (int i=1;i<n;i<<=1) {
		for (int j=0;j<n;j+=(i<<1)) {
			for (int k=0;k<i;++k) {
				LL u=a[j+k],v=a[j+k+i];
				a[j+k]=(u+v)%MOD;
				a[j+k+i]=(u-v+MOD)%MOD;
			}
		}
	}
	if (f==-1) for (int i=0;i<n;++i) a[i]/=n;
}

酱的

void FWT(int *a,int n,int f) {
	for (int i=1;i<n;i<<=1) {
		for (int j=0;j<n;j+=(i<<1)) {
			for (int k=0;k<i;++k) {
				int u=a[j+k],v=a[j+k+i];
				a[j+k]=(u+v)%MOD,a[j+k+i]=(u+MOD-v)%MOD;
				if (f==-1) {
					a[j+k]=1LL*a[j+k]*ny2%MOD;
					a[j+k+i]=1LL*a[j+k+i]*ny2%MOD;
				}
			}
		}
	}
}

以上两种都是对的。考虑第一种做法,那么我们可以把膜数*n,最后FWT回来的时候除掉n就可以了
膜数变得很大因此需要快速乘黑科技

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define copy(x,t) memcpy(x,t,sizeof(x))

typedef long long LL;
const int N=2000005;

LL a[N],b[N],c[N],d[N],e[N];

LL MOD;

LL mul(LL x,LL y) {
	LL res=x*y-(LL)((long double)x/MOD*y+0.1)*MOD;
	return (res%MOD+MOD)%MOD;
}

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void FWT(LL *a,int n,int f) {
	for (int i=1;i<n;i<<=1) {
		for (int j=0;j<n;j+=(i<<1)) {
			for (int k=0;k<i;++k) {
				LL u=a[j+k],v=a[j+k+i];
				a[j+k]=(u+v)%MOD;
				a[j+k+i]=(u-v+MOD)%MOD;
			}
		}
	}
	if (f==-1) for (int i=0;i<n;++i) a[i]/=n;
}

int main(void) {
	int n; LL m,lim;
	scanf("%d%lld%lld",&n,&m,&MOD);
	lim=1LL<<n; MOD*=lim;
	rep(i,0,lim-1) a[i]=read();
	rep(i,0,lim-1) c[i]=c[i>>1]+(i&1);
	rep(i,0,n) b[i]=read();
	rep(i,0,lim-1) d[i]=b[c[i]];
	FWT(d,lim,1); copy(e,d);
	for (m--;m;m>>=1) {
		if (m&1) for (int i=0;i<lim;++i) e[i]=mul(e[i],d[i]);
		for (int i=0;i<lim;++i) d[i]=mul(d[i],d[i]);
	}
	FWT(a,lim,1);
	for (int i=0;i<lim;++i) a[i]=mul(a[i],e[i]);
	FWT(a,lim,-1);
	for (int i=0;i<lim;++i) printf("%lld\n", a[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/87925783