beginend

只要在路上,就没有到不了的远方

Codeforces 914G Sum the Fibonacci 集合幂级数

题意

给出一个长度为n的数组s,定义一个五元组(a,b,c,d,e)是优秀的当且仅当
1a,b,c,d,en
存在某个i满足(sa | sb) & sc & (sd ^ se) = 2^i
且 sa & sb = 0
对于所有合法五元组求f(sa|sb) * f(sc) * f(sd^se)的和,其中f(x)表示斐波那契数列第x项。
n106,si<217

分析

强行模板三合一。。。
对原数组分别做对称差卷积和子集卷积,然后再做and卷积就好了。
对称差卷积就是fwt,and卷积的话就是反过来的or卷积,子集卷积就是对占位幂级数做卷积就好了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=20;
const int M=140005;
const int MOD=1000000007;
const int ny2=(MOD+1)/2;

int n,m,bin[N],fib[M],f[N][M],a[M],b[M],c[M],cnt[M];

void solve1()
{
    for (int i=0;i<bin[n];i++) f[cnt[i]][i]+=a[i];
    for (int i=0;i<=n;i++)
        for (int j=0;j<n;j++)
            for (int k=0;k<bin[n];k++)
                if (k&bin[j]) (f[i][k]+=f[i][k^bin[j]])%=MOD;
    for (int i=n;i>=0;i--)
        for (int j=0;j<bin[n];j++)
        {
            int w=0;
            for (int k=0;k<=i;k++) (w+=(LL)f[k][j]*f[i-k][j]%MOD)%=MOD;
            f[i][j]=w;
        }
    for (int i=0;i<=n;i++)
        for (int j=0;j<n;j++)
            for (int k=0;k<bin[n];k++)
                if (k&bin[j]) (f[i][k]+=MOD-f[i][k^bin[j]])%=MOD;
    for (int i=0;i<bin[n];i++) a[i]=(LL)f[cnt[i]][i]*fib[i]%MOD;
}

void solve2()
{
    for (int i=0;i<bin[n];i++) b[i]=(LL)b[i]*fib[i]%MOD;
}

void FWT(int *a,int l,int r,int c)
{
    if (l==r) return;
    int mid=(l+r)/2,L=r-mid;
    FWT(a,l,mid,c);FWT(a,mid+1,r,c);
    for (int i=l;i<=mid;i++)
    {
        int u=a[i],v=a[i+L];
        if (c==1) a[i]=(u+v)%MOD,a[i+L]=(u+MOD-v)%MOD;
        else a[i]=(LL)(u+v)*ny2%MOD,a[i+L]=(LL)(u+MOD-v)*ny2%MOD;
    }
}

void solve3()
{
    FWT(c,0,bin[n]-1,1);
    for (int i=0;i<bin[n];i++) c[i]=(LL)c[i]*c[i]%MOD;
    FWT(c,0,bin[n]-1,-1);
    for (int i=0;i<bin[n];i++) c[i]=(LL)c[i]*fib[i]%MOD;
}

void FMT(int *f,int c)
{
    for (int i=0;i<n;i++)
        for (int j=bin[n]-1;j>=0;j--)
            if (!(j&bin[i])) (f[j]+=c*f[j^bin[i]])%=MOD;
}

void solve4()
{
    FMT(a,1);FMT(b,1);FMT(c,1);
    for (int i=0;i<bin[n];i++) a[i]=(LL)a[i]*b[i]%MOD*c[i]%MOD;
    FMT(a,-1);
    int ans=0;
    for (int i=0;i<n;i++) (ans+=a[bin[i]])%=MOD;
    printf("%d",(ans+MOD)%MOD);
}

int main()
{
    n=17;scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        int x;scanf("%d",&x);
        a[x]++;b[x]++;c[x]++;
    }
    bin[0]=fib[1]=1;
    for (int i=1;i<=n;i++) bin[i]=bin[i-1]*2;
    for (int i=1;i<bin[n];i++) cnt[i]=cnt[i>>1]+(i&1);
    for (int i=2;i<bin[n];i++) fib[i]=(fib[i-1]+fib[i-2])%MOD;
    solve1();
    solve2();
    solve3();
    solve4();
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33229466/article/details/80694807
个人分类: 集合幂级数
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭