[集训]FWT基础练习题

Posted greenduck

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[集训]FWT基础练习题相关的知识,希望对你有一定的参考价值。

题意

给出n个长度为20的二进制数和数字k,每次询问给出一个二进制数,问从n个数中挑k个数(不能重复)的按位或能包含询问的组合有多少个。数字均小于等于5E5,1s。


 

思考

强行算出2^20个答案,再O(1)询问。

可知按位或的FWT能够将两个数组融合成新的数组。假设Fk表示挑出k个数字能组成的所有可能的,A为原始的桶数组,可知Fk[i]=(Fk-1 或运算FWT A)[i]-(k-1)Fk-1[i],后面减法的目的是减去数被重复选择的部分。

再观察FWT其实是线性变换,因此Fk[i]可以预先乘上k方便下一次计算。因此最开始只要乘上某个组合数即可。

最后根据按位与FWT可得到所有的答案。总复杂度O(nlogn)。


 

代码

技术图片
 1 #pragma GCC optimize 2
 2 #include<bits/stdc++.h>
 3 #define mod 1000000007
 4 using namespace std;
 5 typedef long long int ll;
 6 const int maxn=1E6+5E5+5;
 7 const int LEN=4;
 8 const int G=1<<LEN;
 9 ll n,k,m,a[maxn],b[maxn],c[maxn],d[maxn];
10 ll fac[maxn],inv[maxn];
11 string str;
12 inline int get(string str)
13 
14     int sum=0;
15     for(int i=0;i<LEN;++i)
16         sum=sum*2+str[i]-0;
17     return sum;
18 
19 ll qpow(ll x,ll y)
20 
21     ll ans=1,base=x;
22     while(y)
23     
24         if(y&1)
25             ans=ans*base%mod;
26         base=base*base%mod;
27         y>>=1;
28     
29     return ans;
30 
31 void init()
32 
33     fac[0]=1;
34     for(int i=1;i<=500000;++i)
35         fac[i]=fac[i-1]*i%mod;
36     inv[500000]=qpow(fac[500000],mod-2);
37     for(int i=500000-1;i>=0;--i)
38         inv[i]=inv[i+1]*(i+1)%mod;
39 
40 void FWT(ll*A,int t1,int t2)
41 
42     for(int len=2;len<=G;len<<=1)
43         for(int i=0;i<G/len;++i)
44             for(int j=0;j<len/2;++j)
45             
46                 ll a=A[i*len+j],b=A[i*len+j+len/2];
47                 A[i*len+j]=(a+b*t1)%mod;
48                 A[i*len+j+len/2]=(b+a*t2)%mod;
49             
50 
51 template<class T>void copy(T*a,T*b,int x)
52 
53     for(int i=0;i<x;++i)
54         a[i]=b[i];
55 
56 int main()
57 
58     ios::sync_with_stdio(false);
59     init();
60     cin>>n>>k>>m;
61     for(int i=1;i<=n;++i)
62     
63         cin>>str;
64         ++a[get(str)];
65     
66     copy(c,a,G);
67     FWT(a,0,1);
68     for(int i=0;i<G;++i)
69     
70         if(a[i]>=k)
71             a[i]=fac[a[i]]*inv[a[i]-k]%mod;
72         else
73             a[i]=0;
74     
75     FWT(a,0,-1);
76     /*
77     for(int i=2;i<=k;++i)
78     
79         copy(d,a,G);
80         FWT(a,0,1);
81         copy(b,c,G);
82         FWT(b,0,1);
83         for(int j=0;j<G;++j)
84             a[j]=a[j]*b[j]%mod;
85         FWT(a,0,-1);
86         for(int j=0;j<G;++j)
87             a[j]=(a[j]-d[j]*(i-1)+mod)%mod;
88     
89     */
90     FWT(a,1,0);
91     while(m--)
92     
93         cin>>str;
94         cout<<a[get(str)]*inv[k]%mod<<endl;
95     
96     return 0;
97 
View Code

 

以上是关于[集训]FWT基础练习题的主要内容,如果未能解决你的问题,请参考以下文章

蓝桥杯集训100题scratch水仙花数 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第18题

蓝桥杯集训100题scratch售票找零 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第23题

蓝桥杯集训100题scratch数字计算 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第16题

蓝桥杯集训100题scratch售票找零 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第23题

蓝桥杯集训100题scratch完美数 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第19题

蓝桥杯集训100题scratch摘苹果 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第21题