51nod 1773 A国的贸易 FWT

题意

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取模。
n<=20 t<=10^9

分析

f(i,S) f ( i , S ) 表示进行了 i i 轮后第 S S 个城市的货物量, g(T)=1 g ( T ) = 1 满足 T=2i T = 2 i T=0 T = 0
不难发现 f(i,S)=[TxorA=S]g(T)f(i1,A) f ( i , S ) = ∑ [ T x o r A = S ] g ( T ) f ( i − 1 , A )
直接FWT+快速幂即可。

代码

#include
#include
#include
#include
#include
using namespace std;

typedef long long LL;

const int N=1048580;
const int MOD=1000000007;
const int ny2=(MOD+1)/2;

int n,g[N],f[N],bin[25],t,stack[20];

int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void pri(int x)
{
    if (!x) {putchar('0');return;}
    int top=0;
    while (x) stack[++top]=x%10,x/=10;
    while (top) putchar(stack[top--]+'0');
}

void mod(int &x) {x-=x>=MOD?MOD:0;}

int ksm(int x,int y)
{
    int ans=1;
    while (y)
    {
        if (y&1) ans=(LL)ans*x%MOD;
        x=(LL)x*x%MOD;y>>=1;
    }
    return ans;
}

void FWT(int *a,int l,int r)
{
    if (l==r) return;
    int len=(r-l+1)/2,mid=(l+r)/2;
    FWT(a,l,mid);FWT(a,mid+1,r);
    for (int i=0;iint u=a[l+i],v=a[l+len+i];
        mod(a[l+i]=u+v);mod(a[l+len+i]=u+MOD-v);
    }
}

void DWT(int *a,int l,int r)
{
    if (l==r) return;
    int len=(r-l+1)/2,mid=(l+r)/2;
    DWT(a,l,mid);DWT(a,mid+1,r);
    for (int i=0;iint u=a[l+i],v=a[l+len+i];
        mod(a[l+i]=(LL)(u+v)*ny2%MOD);mod(a[l+len+i]=(LL)(u+MOD-v)*ny2%MOD);
    }
}

int main()
{
    n=read();t=read();
    bin[0]=1;
    for (int i=1;i<=n;i++) bin[i]=bin[i-1]*2;
    g[0]=1;
    for (int i=0;i1;
    for (int i=0;i0,bin[n]-1);FWT(f,0,bin[n]-1);
    for (int i=0;i0,bin[n]-1);
    for (int i=0;iputchar(' ');
    return 0;
}

你可能感兴趣的:(集合幂级数)