• CF 914G Sum the Fibonacci——子集卷积


    题目:http://codeforces.com/contest/914/problem/G

    第一个括号可以子集卷积;第三个括号可以用 FWT 异或卷积;这样算出选两个数组成 x 的方案数;三个部分的方案数分别乘上 f[ x ] 再一起与卷积即可。

    注意子集卷积的时候不要改 tp[ i ][ s ] ,因为要的是恰好两个数拼起来,没有改过的(但是做过 FMT 的) tp[ i ][ s ] 存的是初值,表示选 1 个数的方案数。

      所以如果可以选任意多个数,就可以像背包一样, tp[ j ][ s ] 用的改过的, tp[ i-j ][ s ] 用没改过的。

    累计完 tp[ i ][ s ] 的时候,要在 i 这一层 iFMT 回去,再贡献给 a[ s ] ,不要直接加到 a[ s ] 上、做完所有的 i 之后再 iFMT 回去,因为 iFMT 只能弄回去对于同一个 i 的。

    卷积的时候不要对 i - j == j 的情况去重,因为可以选重复的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mx(int a,int b){return a>b?a:b;}
    const int K=17,N=(1<<K)+5,mod=1e9+7;
    int f[N],a[N],b[N],c[N],bin[K+5],len,bh;
    int ct[N],tp[K+5][N];
    void upd(int &x){x>=mod?x-=mod:0;}
    void init()
    {
      bin[0]=1;for(int i=1;i<=K;i++)bin[i]=bin[i-1]<<1;
      for(int s=1,j=bin[K];s<j;s++)ct[s]=ct[s-(s&-s)]+1;
      f[0]=0;f[1]=1;for(int i=2,j=bin[K];i<j;i++)f[i]=f[i-1]+f[i-2],upd(f[i]);
    }
    void fwt_and(int *a,bool fx)
    {
      for(int R=2;R<=len;R<<=1)
        for(int i=0,m=R>>1;i<len;i+=R)
          for(int j=0;j<m;j++)
        a[i+j]+=(fx?mod-a[i+m+j]:a[i+m+j]),upd(a[i+j]);
    }
    void dv2(int &x){if(x&1)x=(x+mod)>>1; else x>>=1;}
    void fwt_xor(int *a,bool fx)
    {
      for(int R=2;R<=len;R<<=1)
        for(int i=0,m=R>>1;i<len;i+=R)
          for(int j=0;j<m;j++)
        {
          int x=a[i+j],y=a[i+m+j];
          a[i+j]=x+y; a[i+m+j]=x+mod-y;
          upd(a[i+j]); upd(a[i+m+j]);
          if(fx)dv2(a[i+j]),dv2(a[i+m+j]);
        }
    }
    void fmt(int *a,bool fx)
    {
      for(int i=1;i<len;i<<=1)
        for(int s=0;s<len;s++)
          if(s&i)a[s]+=(fx?mod-a[s^i]:a[s^i]),upd(a[s]);
    }
    void cz()
    {
      int t[N];
      for(int i=0;i<=bh;i++)fmt(tp[i],0);//<= not <
      for(int i=0;i<=bh;i++)
        {
          for(int s=0;s<len;s++)t[s]=0;
          for(int j=0;j<=i;j++)
        for(int s=0;s<len;s++)
          t[s]=(t[s]+(ll)tp[j][s]*tp[i-j][s])%mod;
          fmt(t,1);
          for(int s=0;s<len;s++)
        if(i==ct[s])a[s]+=t[s],upd(a[s]);
        }
      /*
      for(int i=0;i<=bh;i++)
        {
          for(int j=0;j<=i;j++)
        for(int s=0;s<len;s++)
          {
            if(i!=ct[s])continue;//
            a[s]=(a[s]+(ll)tp[j][s]*tp[i-j][s])%mod;//i-j==j is ok!
          }
        }
      fmt(a,1);
      */
    }
    int main()
    {
      init();int n=rdn(),mx=0;
      for(int i=1,d;i<=n;i++)
        {
          d=rdn();mx=Mx(mx,d);
          tp[ct[d]][d]++;c[d]++;b[d]+=f[d];upd(b[d]);
        }
      for(bh=1;bin[bh]<=mx;bh++);len=bin[bh];
      cz();
      fwt_xor(c,0);for(int i=0;i<len;i++)c[i]=(ll)c[i]*c[i]%mod;fwt_xor(c,1);
      for(int i=0;i<len;i++)a[i]=(ll)a[i]*f[i]%mod;
      for(int i=0;i<len;i++)c[i]=(ll)c[i]*f[i]%mod;
      fwt_and(a,0); fwt_and(b,0); fwt_and(c,0);
      for(int i=0;i<len;i++)a[i]=(ll)a[i]*b[i]%mod*c[i]%mod;
      fwt_and(a,1);
      int ans=0;
      for(int i=1;i<len;i<<=1)ans+=a[i],upd(ans);
      printf("%d
    ",ans);
      return 0;
    }
  • 相关阅读:
    20180925-2 功能测试
    【PL/SQL编程】循环语句
    【PL/SQL编程】条件语句
    【PL/SQL编程】变量和常量
    【PL/SQL编程】数据类型说明
    【PL/SQL编程】注释说明
    【PL/SQL编程】SQL与PL/SQL的区别
    【SQL查询】查询结果翻译成其他值_decode
    【SQL查询】日期的转换_to_date/to_char
    【SQL查询】视图_view
  • 原文地址:https://www.cnblogs.com/Narh/p/10259830.html
Copyright © 2020-2023  润新知