zoukankan      html  css  js  c++  java
  • 【CF914G】Sum the Fibonacci 快速??变换模板

    【CF914G】Sum the Fibonacci

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

    1. $1le a,b,c,d,ele n$
    2. $(s_a|s_b) & s_c & (s_d $^$ s_e)=2^i$,i是某个整数
    3. $s_a & s_b=0$

    求$sum f(s_a|s_b) * f(s_c) * f(s_d $^$ s_e)$,f是斐波那契数列,对于所有合法的五元组(a,b,c,d,e)。答案模$10^9+7$。

    $1le nle 10^6,0le s_i< 2^{17}$

    题解:说白了就是求:子集和卷积,异或卷积,与卷积。后面两个好求,学了一发子集和卷积。说白了就是强行加了一个占位多项式,即将数组多开一维记录子集中1的个数。然后合并时相当于背包合并,时间复杂度$O(n^22^n)$。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    typedef long long ll;
    const int maxn=(1<<17)+4;
    const ll P=1000000007;
    const ll inv=500000004;
    ll a[maxn],c[maxn],d[maxn];
    ll fa[maxn][18],fb[maxn][18],f[maxn];
    ll ans;
    int cnt[maxn];
    int n,len;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd();
    	int h,i,j,k,x,y,v;
    	f[1]=cnt[1]=1;
    	len=1<<17;
    	for(i=2;i<len;i++)	f[i]=(f[i-1]+f[i-2])%P,cnt[i]=cnt[i-(i&-i)]+1;
    	for(i=1;i<=n;i++)	v=rd(),fa[v][cnt[v]]++,d[v]++,c[v]=(c[v]+f[v])%P;
    	for(h=1;h<len;h<<=1)	for(i=0;i<len;i++)	if(i&h)	for(j=0;j<=17;j++)
    		fa[i][j]=(fa[i][j]+fa[i-h][j])%P;
    	for(i=0;i<len;i++)	for(j=0;j<=17;j++)	for(k=0;k<=j;k++)
    		fb[i][j]=(fb[i][j]+fa[i][k]*fa[i][j-k])%P;
    	for(h=1;h<len;h<<=1)	for(i=0;i<len;i++)	if(i&h)	for(j=0;j<=17;j++)
    		fb[i][j]=(fb[i][j]-fb[i-h][j]+P)%P;
    	for(i=0;i<len;i++)	a[i]=(a[i]+f[i]*fb[i][cnt[i]])%P;
    	for(h=1;h<len;h<<=1)	for(i=0;i<len;i++)	if(i&h)
    		x=d[i-h],y=d[i],d[i-h]=(x+y)%P,d[i]=(x-y+P)%P;
    	for(i=0;i<len;i++)	d[i]=d[i]*d[i]%P;
    	for(h=1;h<len;h<<=1)	for(i=0;i<len;i++)	if(i&h)
    		x=d[i-h],y=d[i],d[i-h]=(x+y)*inv%P,d[i]=(x-y+P)*inv%P;
    	for(i=0;i<len;i++)	d[i]=d[i]*f[i]%P;
    	for(h=1;h<len;h<<=1)	for(i=0;i<len;i++)	if(!(i&h))
    		a[i]=(a[i]+a[i+h])%P,c[i]=(c[i]+c[i+h])%P,d[i]=(d[i]+d[i+h])%P;
    	for(i=0;i<len;i++)	a[i]=a[i]*c[i]%P*d[i]%P;
    	for(h=1;h<len;h<<=1)	for(i=0;i<len;i++)	if(!(i&h))
    		a[i]=(a[i]-a[i+h]+P)%P;
    	for(i=0;i<17;i++)	ans=(ans+a[1<<i])%P;
    	printf("%lld",ans);
    	return 0;
    }
  • 相关阅读:
    Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。
    C++ 复制到粘贴板
    编译防火墙——C++的Pimpl惯用法解析
    字符串输出
    windows路径操作API函数
    Boost解析xml——xml写入
    智能指针shared_ptr
    Boost 解析xml——插入Item
    ListCtrl添加右键菜单(在对话框类中)
    抓包工具Charles的使用说明
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8445258.html
Copyright © 2011-2022 走看看