CF 914 G Sum the Fibonacci —— 子集卷积,FWT

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

其实就是把各种都用子集卷积和FWT卷起来算即可;

注意乘 Fibonacci 数组的位置;

子集卷积时不能一边做一边更新卷积的数组!

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=0; ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘,ch=getchar();
  return f?ret:-ret;
}
int Max(int x,int y){return x>y?x:y;}
int const xm=(1<<18)+5,mod=1e9+7;
int n,p[xm],F[xm],f[20][xm],g[xm],h[xm],t[xm],bin[25],cnt[xm],inv2,lm;
ll pw(ll a,int b){ll ret=1; for(;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod; return ret;}
int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;}
int cal(int s){int ret=0; while(s)ret+=(s&1),s>>=1; return ret;}
int get(int x){int ret=0; while(x)ret++,x>>=1; return ret;}
void init()
{
  F[0]=0; F[1]=1;
  for(int i=2;i<bin[lm];i++)F[i]=upt(F[i-1]+F[i-2]);
}
void fmt(int *a,int tp)
{
  for(int d=1;d<bin[lm];d<<=1)
    for(int s=0;s<bin[lm];s++)
      if(s&d)a[s]=upt(a[s]+a[s^d]*tp);
}
void fwt1(int *a,int tp)//&
{
  for(int mid=1;mid<bin[lm];mid<<=1)
    for(int j=0,len=(mid<<1);j<bin[lm];j+=len)
      for(int k=0;k<mid;k++)
    a[j+k]=upt(a[j+k]+a[j+mid+k]*tp);
}
void fwt2(int *a,int tp)//^
{
  for(int mid=1;mid<bin[lm];mid<<=1)
    for(int j=0,len=(mid<<1);j<bin[lm];j+=len)
      for(int k=0;k<mid;k++)
    {
      int x=a[j+k],y=a[j+mid+k];
      a[j+k]=upt(x+y); a[j+mid+k]=upt(x-y);
      if(tp==-1)a[j+k]=(ll)a[j+k]*inv2%mod,a[j+mid+k]=(ll)a[j+mid+k]*inv2%mod;
    }
}
int main()
{
  n=rd(); lm=18;
  bin[0]=1; for(int i=1;i<=lm;i++)bin[i]=bin[i-1]*2;
  for(int s=0;s<bin[lm];s++)cnt[s]=cal(s);
  int mx=0;
  for(int i=1,x;i<=n;i++)x=rd(),p[x]++,mx=Max(mx,x);
  lm=get(mx)+1; init();
  for(int s=0;s<bin[lm];s++)f[cnt[s]][s]=p[s];
  for(int i=0;i<lm;i++)fmt(f[i],1);
  /*
  for(int i=1;i<lm;i++)
    {
      for(int j=0;j<=i;j++)
    for(int s=0;s<bin[lm];s++)
      f[i][s]=(f[i][s]+(ll)f[j][s]*f[i-j][s])%mod;
      for(int s=0;s<bin[lm];s++)if(cnt[s]!=i)f[i][s]=0;
    }
  for(int i=0;i<lm;i++)fmt(f[i],-1);
  for(int s=0;s<bin[lm];s++)g[s]=f[cnt[s]][s];
  */
  for(int i=1;i<lm;i++)
    {
      memset(t,0,sizeof t);
      for(int j=0;j<=i;j++)
    for(int s=0;s<bin[lm];s++)
      t[s]=(t[s]+(ll)f[j][s]*f[i-j][s])%mod;
      fmt(t,-1);
      for(int s=0;s<bin[lm];s++)
    if(cnt[s]==i)g[s]=upt(g[s]+t[s]);
    }

  for(int s=0;s<bin[lm];s++)h[s]=p[s];
  inv2=pw(2,mod-2); fwt2(h,1);
  for(int s=0;s<bin[lm];s++)h[s]=(ll)h[s]*h[s]%mod;
  fwt2(h,-1);

  for(int s=0;s<bin[lm];s++)g[s]=(ll)g[s]*F[s]%mod;
  for(int s=0;s<bin[lm];s++)h[s]=(ll)h[s]*F[s]%mod;
  for(int s=0;s<bin[lm];s++)p[s]=(ll)p[s]*F[s]%mod;
  fwt1(g,1); fwt1(h,1); fwt1(p,1);
  for(int s=0;s<bin[lm];s++)g[s]=(ll)g[s]*h[s]%mod*p[s]%mod;
  fwt1(g,-1); int ans=0;
  for(int i=0;i<lm;i++)ans=upt(ans+g[bin[i]]);
  printf("%d\n",ans);
  return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/10259239.html

时间: 2024-11-09 20:12:29

CF 914 G Sum the Fibonacci —— 子集卷积,FWT的相关文章

CF914G Sum the Fibonacci FWT、子集卷积

传送门 一道良心的练习FWT和子集卷积的板子-- 具体来说就是先把所有满足\(s_a \& s_b = 0\)的\(s_a \mid s_b\)的值用子集卷积算出来,将所有\(s_a \oplus s_b\)用xor卷积算出来,把斐波那契数代进去,然后将三个数组and卷积,最后取\(2^i (i \in Z)\)的位置的答案的和 #include<bits/stdc++.h> //this code is written by Itst using namespace std; int

【CF914G】Sum the Fibonacci 快速??变换模板

[CF914G]Sum the Fibonacci 题解:给你一个长度为n的数组s.定义五元组(a,b,c,d,e)是合法的当且仅当: 1. $1\le a,b,c,d,e\le 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

Future Failure CodeForces - 838C (博弈论,子集卷积)

大意: 两人轮流操作一个长$n$, 只含前$k$种小写字母的串, 每次操作删除一个字符或者将整个串重排, 每次操作后得到的串不能和之前出现过的串相同, 求多少种串能使先手必胜. 找下规律发现$n$为奇数必胜, 否则假设$a_i$为字符$i$出现次数, 如果$\frac{n!}{a_1!a_2!...a_k!}$为奇数则必败 $n!$中$2$的幂次为n-__builtin_popcount(n) 所以必败就等价于$a_1+...+a_n=a_1|...|a_n$ 设$f_{i,j}$表示前$i$个

FMT 和 子集卷积

FMT 和 子集卷积 FMT 给定数列 $ a_{0\dots 2^{k}-1} $ 求 $ b $ 满足 $ b_{s} = \sum_{i\in s} a_i $ 实现方法很简单, for( i in 0..n-1 ) for( j in 0..2^n-1) if( j & ( 1 << i ) ) a[j] += a[j ^ ( 1 << i )] 然后称为 $ B = FMT(A) $ ,快速莫比乌斯变换 想要还原也很简单,把代码反着写: for( i in n-1

hdu 6057 Kanade&#39;s convolution(子集卷积)

题解: 然后就是接下来如何fwt 也就是如何处理bit(x) - bit(y) = bit(k)这个条件. 其实就是子集卷积. 把bit(x)和bit(y)划分成两个集合,然后就是子集卷积的形式. 这里设两个新的数组 A[bit(y)][y], B[bit(x)][x],代表拆出来的相应数组 然后对这两个数组做fwt,得到其点值表示,然后直接在外层枚举x和y的大小然后做卷积即可. 这样说可能很抽象,其实贴出代码就很清楚了 #include <iostream> #include <vec

CF 577B Modulo Sum

题意:给一个长度为n的正整数序列,问能不能找到一个不连续的子序列的和可以被m整除. 解法:抽屉原理+dp.首先当m<n时一定是有答案的,因为根据抽屉原理,当得到这个序列的n个前缀和%m时,一定会出现两个相同的数,这两个前缀和相减得到的序列和一定可以被m整除.当n<=m时,dp一下就可以了,类似01背包. 其实可以直接dp,只要滚动数组+在找到答案时break就可以了,同样因为抽屉原理,当枚举到第m+1个物品的时候就一定会得到解,所以最后复杂度O(m^2). 代码: #include<st

fibonacci卷积公式的使用

Fibonacci数列的定义如下: f(n) = f(n - 1) + f(n - 2) (n >= 3) f(1) = 1, f(2) = 2 f(0)可定义为1. 用归纳法可以证明性质: f(n + m) = f(m - 1)f(n + 1) + f(m - 2)f(n)  (m>= 2) 利用这条性质,我们可以将比较大的n的Fibonacci数转化成比较小的Fibonacci数,从而使计算起来更为方便. 这里有一个问题: Fibonacii数列 Fn (mod k) 的循环节长度是多少?

集合并卷积的三种求法

也许更好的阅读体验 本文主要内容是对武汉市第二中学吕凯风同学的论文<集合幂级数的性质与应用及其快速算法>的理解 定义 集合幂级数 为了更方便的研究集合的卷积,引入集合幂级数的概念 集合幂级数也是形式幂级数的一种,只是集合的一种表现形式,无需考虑收敛或发散的含义 定义一个集合 \(S\) 的集合幂级数为 \(f\) ,那么我们就可以把集合 \(S\) 表示为如下形式 \(\begin{aligned}f=\sum _{T\subseteq S}f_{T}\cdot x^{T}\end{align

linq to sql (Group By/Having/Count/Sum/Min/Max/Avg操作符) (转帖)

http://wenku.baidu.com/link?url=2RsCun4Mum1SLbh-LHYZpTmGFMiEukrWAoJGKGpkiHKHeafJcx2y-HVttNMb1BqJpNdwaOpCflaajFY6k36IoCH_D82bk2ccu468uzDRXvG 基于LINQ+to+Entity数据访问技术的应用研究 Group By/Having操作符 适用场景:分组数据,为我们查找数据缩小范围. 说明:分配并返回对传入参数进行分组操作后的可枚举对象.分组:延迟 1.简单形式: