51NOD 1773 A国的贸易

题目

这里

对于每一对可以贸易的城市 u , v u,v u,v,满足 c l a c ( u , v ) = 1 clac(u,v)=1 clac(u,v)=1,即满足 u   x o r   v = 2 k u~xor~v=2^k u xor v=2k,变换一下成为
u   x o r   2 k = v u~xor~2^k=v u xor 2k=v,那么 u u u便可以给每一个 u   x o r   2 k u~xor~2^k u xor 2k做出 A u A_{u} Au的贡献

那么可以构造一个数列B满足:
B 2 k = 1 , B 0 = 1 , B_{2^k}=1,B_{0}=1, B2k=1,B0=1,其余情况为 0 0 0
那么将 A A A x o r xor xor卷积卷 B   n B~n B n次即可得到答案

可以FWT加速。。。时间复杂度 O ( n l o g 2 T ) O(nlog_{2}T) O(nlog2T)

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<algorithm>

#define maxn 2000005
#define MOD 1000000007
#define inv2 500000004

using namespace std;

inline int getint()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

int T,n;
long long ans;
bool not_prime[maxn];
int prime[maxn],cnt;
long long A[maxn];
long long a[maxn];
int rev[maxn];

inline void FWT_xor(long long *a,int inv)
{
	for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int mid=1;mid<n;mid<<=1)
		for(int j=0,tmp=mid<<1;j<n;j+=tmp)
			for(int k=0;k<mid;++k)
			{
				int x=a[j+k],y=a[mid+j+k];
				a[j+k]=(x+y)%MOD,a[mid+j+k]=(x+MOD-y)%MOD;
				if(inv==-1)(a[j+k]*=inv2)%=MOD,(a[mid+j+k]*=inv2)%=MOD;
			}
}

inline void putint(long long num)
{
	if(num>9)putint(num/10);
	putchar(num%10+48);
}

int main()
{
	n=getint(),T=getint();
	for(int i=0;i<(1<<n);++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(n-1));
	for(int i=0;i<n;++i)a[1<<i]=1;a[0]=1;
	n=1<<n;
	for(int i=0;i<n;++i)A[i]=getint();
	FWT_xor(A,1),FWT_xor(a,1);
	while(T)
	{
		if(T&1)for(int i=0;i<n;i++)(A[i]*=a[i])%=MOD;
		for(int i=0;i<n;i++)(a[i]*=a[i])%=MOD;T>>=1;
	}
	FWT_xor(A,-1);
	for(int i=0;i<n;++i)
	{
		putint(A[i]);
		if(i==n-1)putchar('\n');
		else putchar(' ');
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值