51nod 1773 A国的贸易 [FWT]

题意

有2^n个国家(0~2^n-1编号),每个国家最初有a[i]个货物。每过一天,假如编号i与编号j异或之后二进制1的个数为1,则国家i会增加上一天国家j的货物,国家j类似。求t天之后各个国家的货物数目。

题解

对于第t天交易,我们可以得到以下式子:

a(t,i)=a(t1,i)+ij==2ka(t1,j) a ( t , i ) = a ( t − 1 , i ) + ∑ i ⊕ j == 2 k a ( t − 1 , j )

我们可以将公式变换一下
a(t,i)=a(t1,i)+j2k==ia(t1,j) a ( t , i ) = a ( t − 1 , i ) + ∑ j ⊕ 2 k == i a ( t − 1 , j )

这样我们就可以用FWT对原数组快速修改了。定义num数组是更新数组,我们将num[0],num[1],num[2]..num[2^k]全部标记为1,对于过去一天,我们可以得到答案数组 F1(F(a)F(b)) F − 1 ( F ( a ) ∗ F ( b ) ) 那么做第二天的时候就可以得到 F1(F(a)F(b)F(b)) F − 1 ( F ( a ) ∗ F ( b ) ∗ F ( b ) ) ,所以做t天的时候答案是 F1(F(a)F(b)t) F − 1 ( F ( a ) ∗ F ( b ) t )

AC代码

#include<stdio.h>
#include<string.h>
#define mod 1000000007 
typedef long long ll;

ll rev=mod+1>>1;
void FWT(ll a[],ll n)    
{    
    for(ll d=1;d<n;d<<=1)    
        for(ll m=d<<1,i=0;i<n;i+=m)    
            for(ll j=0;j<d;j++)    
            {    
                ll x=a[i+j],y=a[i+j+d];    
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;    
                //xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;    
                //and:a[i+j]=x+y;    
                //or:a[i+j+d]=x+y;    
            }    
}    

void UFWT(ll a[],ll n)    
{    
    for(ll d=1;d<n;d<<=1)    
        for(ll m=d<<1,i=0;i<n;i+=m)    
            for(ll j=0;j<d;j++)    
            {    
                ll x=a[i+j],y=a[i+j+d];    
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;    
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;    
                //and:a[i+j]=x-y;    
                //or:a[i+j+d]=y-x;    
            }    
}    
ll qmi(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b%2)ans=ans*a%mod;
        a=a*a%mod;
        b/=2;
    }
    return ans;
}

void solve(ll a[],ll b[],ll n,ll m)    
{  
    FWT(a,n);  
    FWT(b,n);  
    for(ll i=0;i<n;i++) a[i]=a[i]*qmi(b[i],m)%mod;    
    UFWT(a,n);  
}

ll a[1<<20|5],num[1<<20|5];
int main()
{
    ll n,m;
    scanf("%lld%lld",&n,&m);
    for(ll i=0;i<(1<<n);i++)
        scanf("%lld",&a[i]);
    num[0]=1;
    for(ll i=0;i<n;i++)
        num[1<<i]=1;
    solve(a,num,(1<<n),m);
    for(ll i=0;i<(1<<n);i++)printf("%lld ",a[i]);
    printf("\n");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值