51nod1773 A国的贸易 FWT+快速幂

9 篇文章 0 订阅

Description


A国是一个神奇的国家。
这个国家有 2n 个城市,每个城市都有一个独一无二的编号 ,编号范围为0~2n-1。
A国的神奇体现在,他们有着神奇的贸易规则。
当两个城市u,v的编号满足calc(u,v)=1的时候,这两个城市才可以进行贸易(即有一条边相连)。
而calc(u,v)定义为u,v按位异或的结果的二进制表示中数字1的个数。

ex:calc(1,2)=2 ——> 01 xor 10 = 11
calc(100,101)=1 ——> 0110,0100 xor 0110,0101 = 1
calc(233,233)=0 ——> 1110,1001 xor 1110,1001 = 0

每个城市开始时都有不同的货物存储量。
而贸易的规则是:
每过一天,可以交易的城市之间就会交易一次。
在每次交易中,当前城市u中的每个货物都将使所有与当前城市u有贸易关系的城市货物量 +1 。
请问 t 天后,每个城市会有多少货物。
答案可能会很大,所以请对1e9+7取模。

Solution


很容易想到设 g [ x ] = [ x = 2 i ] ,    i ∈ N g[x]=[x=2^i],\; i\in N g[x]=[x=2i],iN,那么一次转移的增量等价于 f [ i ] = ∑ j ⊕ k = i f ′ [ j ] ⋅ g [ k ] f[i]=\sum\limits_{j\oplus k=i}f'[j]\cdot g[k] f[i]=jk=if[j]g[k]
光是这样还不能够快速幂,我们只需要设g[0]=1,就可以累计之前的所有贡献了
然后就没了

Code


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

typedef long long LL;
const int MOD=1000000007;
const int ny2=(MOD+1)/2;
const int N=2000005;

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

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) {
				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]=a[j+k]*ny2%MOD;
					a[j+k+i]=a[j+k+i]*ny2%MOD;
				}
			}
		}
	}
}

int main(void) {
	freopen("data.in","r",stdin);
	int n=read(),m=read(),lim=1<<n;
	for (int i=0;i<lim;++i) a[i]=read();
	for (int i=0;i<lim;++i) c[i]=c[i>>1]+(i&1);
	for (int i=0;i<lim;++i) b[i]=(c[i]==1); b[0]=1;
	FWT(b,lim,1); FWT(a,lim,1);
	for (;m;m>>=1) {
		if (m&1) for (int i=0;i<lim;++i) a[i]=a[i]*b[i]%MOD;
		for (int i=0;i<lim;++i) b[i]=b[i]*b[i]%MOD;
	}
	FWT(a,lim,-1);
	for (int i=0;i<lim;++i) printf("%lld ", a[i]%1000000007); puts("");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值