您的位置:首页 > 其它

【FWT】51Nod1773[A国的贸易]题解

2018-01-24 10:38 183 查看

题目概述

有 2n2n 个点,每次 ii 点会使 count(i xor j)=1count(i xor j)=1 的 jj 点增加 aiai 个货物,其中 count(i)count(i) 表示 ii 在二进制下 11 的个数,aiai 表示 ii 点上一次的货物数量。

问时刻 tt 之后,每个点货物的数量。

解题报告

令时刻 tt 的状态为 ftft ,那么根据题意得出:

ft,i=ft−1,i+∑i xor j=2kft−1,j(1)(1)ft,i=ft−1,i+∑i xor j=2kft−1,j

怎么看都疑似异或卷积啊,转化一下:

ft,i=ft−1,i+∑j xor 2k=ift−1,j(2)(2)ft,i=ft−1,i+∑j xor 2k=ift−1,j

这明显就是异或卷积的形式了,构造向量 AA 满足:

A0=1,Ai=[∃2k=i](3)(3)A0=1,Ai=[∃2k=i]

那么 ft=ft−1⊕Aft=ft−1⊕A ,快速幂一下就行了。

示例程序

#include<cstdio>
#include<cctype>
using namespace std;
typedef long long LL;
const int maxn=1<<20,MOD=1e9+7,INV2=MOD+1>>1;

int n,m,A[maxn+5],num[maxn+5];

#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF;return *l++;
}
inline int readi(int &x){
int tot=0,f=1;char ch=readc(),lst='+';
while (!isdigit(ch)) {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while (isdigit(ch)) tot=(tot<<3)+(tot<<1)+(ch^48),ch=readc();
return x=tot*f,Eoln(ch);
}
inline void writei(int x){
static int buf[30],len;len=0;do buf[len++]=x%10,x/=10; while (x);
while (len) putchar(buf[--len]+48);
}
inline void AMOD(int &x,int tem) {if ((x+=tem)>=MOD) x-=MOD;}
inline void FWT(int *a,int n,int f){
for (int k=1;k<n;k<<=1)
for (int i=0;i<n;i+=k<<1)
for (int j=0;j<k;j++){
int x=a[i+j],y=a[i+j+k];
AMOD(a[i+j]=x,y);AMOD(a[i+j+k]=x,MOD-y);
if (f<0) a[i+j]=(LL)a[i+j]*INV2%MOD,a[i+j+k]=(LL)a[i+j+k]*INV2%MOD;
}
}
inline int Pow(int w,int b){
int s=1;
while (b) {if (b&1) s=(LL)s*w%MOD;b>>=1;if (b) w=(LL)w*w%MOD;}
return s;
}
int main(){
readi(n);readi(m);for (int i=0;i<(1<<n);i++) readi(num[i]);
A[0]=1;for (int i=0;i<n;i++) A[1<<i]=1;FWT(A,1<<n,1);FWT(num,1<<n,1);
for (int i=0;i<(1<<n);i++) num[i]=(LL)num[i]*Pow(A[i],m)%MOD;FWT(num,1<<n,-1);
for (int i=0;i<(1<<n)-1;i++) writei(num[i]),putchar(' ');writei(num[(1<<n)-1]);
return putchar('\n'),0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: