Codecraft-18 and Codeforces Round #458 (Div. 1 + Div. 2, combined)G.Sum the Fibonacci(FWT+FMT)

题意

这里写图片描述

  其中 f(x) f ( x ) 表示斐波那契的第 x x 位的值,f(0)=0,f(1)=1 |S|106max{S}<131072 | S | ≤ 10 6 , m a x { S } < 131072

分析

  直接进行FWT和FMT就行了,将S的权值表形式记录为 A[] A [ ] ,那么式子就是:
这里写图片描述
   D[] D [ ] 用FMT求出, F[] F [ ] 用FWTxor求出, G[] G [ ] 用FWTand求出就行了。

Code

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int Fmaxn=(1<<17)+5,mod=1e9+7;
int cnt[Fmaxn],A[Fmaxn],B[18][Fmaxn],C[18][Fmaxn],D[Fmaxn],E[Fmaxn],F[Fmaxn],G[Fmaxn],n,lim,mx,fib[Fmaxn];
namespace {
    inline int Add(const int &x,const int &y) {
        int res=x+y;
        if(res>=mod)
            res-=mod;
        return res;
    }
    inline int Sub(const int &x,const int &y) {
        int res=x-y;
        if(res<0)
            res+=mod;
        return res;
    }
    inline int Mul(const int &x,const int &y) {
        return 1ll*x*y%mod;
    }
    inline int Half(const int &x) {
        return x&1?x+mod>>1:x>>1;
    }
}
inline void FMT(int *x) {
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;++j)
            if(j&i)
                x[j]=Add(x[j],x[j^i]);
}
inline void IFMT(int *x) {
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;++j)
            if(j&i)
                x[j]=Sub(x[j],x[j^i]);
}
inline void FWTand(int *x) {
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=(i<<1))
            for(int k=0;k<i;++k)
                x[j+k]=Add(x[j+k],x[j+k+i]);
}
inline void IFWTand(int *x) {
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=(i<<1))
            for(int k=0;k<i;++k)
                x[j+k]=Sub(x[j+k],x[j+k+i]);
}
inline void FWTxor(int *x) {
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=(i<<1))
            for(int k=0;k<i;++k) {
                int y=x[j+k],z=x[j+k+i];
                x[j+k]=Add(y,z),x[j+k+i]=Sub(y,z);
            }
}
inline void IFWTxor(int *x) {
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=(i<<1))
            for(int k=0;k<i;++k) {
                int y=x[j+k],z=x[j+k+i];
                x[j+k]=Half(Add(y,z)),x[j+k+i]=Half(Sub(y,z));
            }
}
int main() {
    for(int i=1;i<Fmaxn;++i)
        cnt[i]=__builtin_popcount(i);
    fib[1]=1;
    for(int i=2;i<Fmaxn;++i)
        fib[i]=Add(fib[i-1],fib[i-2]);
    read(n);
    for(int i=0,x;i<n;++i)
        read(x),mx=max(mx,x),A[x]++,E[x]++;
    for(n=lim=1;lim<=mx;n++,lim<<=1);
    for(int i=0;i<lim;++i)
        B[cnt[i]][i]=A[i];
    for(int i=0;i<n;++i)
        FMT(B[i]);
    for(int i=0;i<n;++i)
        for(int j=0;i+j<n;++j)
            for(int k=0;k<lim;++k)
                C[i+j][k]=Add(C[i+j][k],Mul(B[i][k],B[j][k]));
    for(int i=0;i<n;++i)
        IFMT(C[i]);
    for(int i=0;i<lim;++i)
        D[i]=C[cnt[i]][i];
    FWTxor(A);
    for(int i=0;i<lim;++i)
        F[i]=Mul(A[i],A[i]);
    IFWTxor(F);
    for(int i=0;i<lim;++i)
        D[i]=Mul(D[i],fib[i]),
        E[i]=Mul(E[i],fib[i]),
        F[i]=Mul(F[i],fib[i]);
    FWTand(D),FWTand(E),FWTand(F);
    for(int i=0;i<lim;++i)
        G[i]=Mul(D[i],Mul(E[i],F[i]));
    IFWTand(G);
    int ans=0;
    for(int i=0;i<n;++i)
        ans=Add(ans,G[1<<i]);
    printf("%d\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值