[CodeForces914G]Sum the Fibonacci

题意:

给你一个长度为 n n 的数组s .定义五元组 (a,b,c,d,e) ( a , b , c , d , e ) 是合法的当且仅当:

①. 1a,b,c,d,en 1 ≤ a , b , c , d , e ≤ n

②. (sa|sb) ( s a | s b ) & sc s c & (sd ( s d ^ se)=2i,iN s e ) = 2 i , i ∈ N

③. sa s a & sb=0 s b = 0

对于所有合法的五元组 (a,b,c,d,e) ( a , b , c , d , e )

f(sa|sb)f(sc)f(sd ∑ f ( s a | s b ) ∗ f ( s c ) ∗ f ( s d ^ se)mod109+7 s e ) mod 10 9 + 7

f0=0,f1=1,fi=fi1+fi2 f 0 = 0 , f 1 = 1 , f i = f i − 1 + f i − 2

1n106,0si<217 1 ≤ n ≤ 10 6 , 0 ≤ s i < 2 17


考虑到 si s i 的范围很小,所以我们考虑记下 cnt[si] c n t [ s i ] 表示 si s i 出现的个数

因为题目要求的是通过 (sa|sb) ( s a | s b ) & sc s c & (sd ( s d ^ se) s e ) 得到的数

那么 f(sa|sb)f(sc)f(sd ∑ f ( s a | s b ) ∗ f ( s c ) ∗ f ( s d ^ se) s e )

=cnt[sa|sb]f(sa|sb) = c n t [ s a | s b ] ∗ f ( s a | s b ) & cnt[sc]f(sc) c n t [ s c ] ∗ f ( s c ) & cnt[sd c n t [ s d ^ se]f(sd s e ] ∗ f ( s d ^ se) s e )

这里的&表示与卷积

考虑 cnt[sa|sb]=[sa c n t [ s a | s b ] = ∑ [ s a & sb=0]cnt[sa]cnt[sb] s b = 0 ] c n t [ s a ] ∗ c n t [ s b ]

其实这就是子集卷积的另外一种表达方式

不会的看 vfk2015 v f k 2015 的集训队论文或者右转这里

cnt[sd c n t [ s d ^ se] s e ] 这个就是 cnt[s] c n t [ s ] 与自己的异或卷积

最后把所有的 cnt c n t 都求出来之后再乘上相应位置的 f f

然后求一遍与卷积,把2i次方项的答案加起来就好了

以上的与卷积,异或卷积(还有或卷积)都可以用 FWT F W T (快速沃尔什变换)求出

这个 FWT F W T 的话我们可以很好的通过背代码理解

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(i,u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=19,M=1<<17|1,P=1e9+7,inv=5e8+4;
typedef int arr[M];
int n,S,ans,Mi[N];arr a[N],b[N],c,d,e,f,p[N],t,pos,cnt;
inline int add(int a,int b){return a+=b,a>=P?a-P:a;}
inline int sub(int a,int b){return a-=b,a<0?a+P:a;}
inline void fmt(int*a,int op(int,int)){
    fp(i,1,n)fp(s,1,S)if(s&Mi[i])
        a[s]=op(a[s],a[s^Mi[i]]);
}
inline void fwt(int*a,int op){
    fp(i,1,n)fp(s,1,S)
        if(s&Mi[i]){
        int o=a[s],t=Mi[i];
        if(op==1)a[s-t]=add(a[s-t],o);
        else if(op==2)a[s]=sub(a[s-t],o),a[s-t]=add(a[s-t],o);
        else a[s]=add(a[s-t],o);
    }
}
inline void ifwt(int*a,int op){
    fp(i,1,n)fp(s,1,S)if(s&Mi[i]){
        int o=a[s],t=Mi[i];
        if(op==1)a[s-t]=sub(a[s-t],o);
        else if(op==2)a[s]=1ll*sub(a[s-t],o)*inv%P,a[s-t]=1ll*add(a[s-t],o)*inv%P;
        else a[s]=sub(o,a[s-t]);
    }
}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    pos[1]=Mi[1]=1;fp(i,2,18)pos[Mi[i]=Mi[i-1]<<1]=i;
    sd(n);int x,y=0;fp(i,1,n)sd(x),++t[x],cmax(y,x);
    S=1;while(S<=y)S<<=1;n=pos[S--];
    fp(i,1,S)cnt[i]=cnt[i>>1]+(i&1);
    f[1]=1;fp(i,2,S)f[i]=add(f[i-1],f[i-2]);
    fp(s,0,S)a[cnt[s]][s]=b[cnt[s]][s]=d[s]=t[s],c[s]=1ll*t[s]*f[s]%P;;
    fwt(d,2);fp(s,0,S)d[s]=1ll*d[s]*d[s]%P;
    ifwt(d,2);fp(s,0,S)d[s]=1ll*d[s]*f[s]%P;
    fp(i,0,n)fmt(a[i],add),fmt(b[i],add);
    fp(i,0,n)fp(j,0,n-i)fp(s,0,S)p[i+j][s]=add(p[i+j][s],1ll*a[i][s]*b[j][s]%P);
    fp(i,0,n)fmt(p[i],sub);fp(s,0,S)e[s]=1ll*p[cnt[s]][s]*f[s]%P;
    fwt(c,1),fwt(d,1),fwt(e,1);
    fp(s,0,S)c[s]=1ll*c[s]*d[s]%P*e[s]%P;
    ifwt(c,1);fp(i,1,n)ans=add(ans,c[Mi[i]]);
    printf("%d",ans);
return Ot(),0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值