状压 FWT P5366题解
第一次看见这题的时候觉得挺牛逼的,然后想了半个小时发现其实还是挺简单(
首先:
首先
那么
观察一下可以知道
然后这玩意儿看上去像是在对“是否拥有一个完整的
注意到这个
这玩意儿好像不太可做。但是好像把
所以重新设状态,
然后这里就是纯纯 Or 卷积了。并且可以发现逆元是将这个数做 FWT 后所有位置取逆元,能够发现显然是
需要注意的是要以点值形式保存,然后做一个子集反演(等价于一次 IFWT)。复杂度是单次
不过嘛,可以考虑计算每一个数对最开始背包的贡献。做一个子集和差不多了。
复杂度
然后我们发现一件事:
统计不包含某个数的方案数时,实际上是将超集全部除以了
然后使用最开始的值减去这一部分,就只剩下了超集的部分除以
由于我们是每次做 IFWT 后取在
于是全部除以
#include<cstdio>
#include<cctype>
typedef unsigned ui;
const ui M=1<<8,mod=1e9+7,inv2=500000004;
ui Q,G,L,X,N,pw2[1024];ui m,p[10],k[10],t[10];double invG,x[10],y[10];ui f[M*M];bool ppc[M*M];
char _INPUT[1<<21|1],_OUTPUT[1<<21|1],*_P1=_INPUT,*_P2=_OUTPUT;
inline void DFS(const ui&id,const ui&S1,const ui&S2,ui x){
if(id==m)return void(++f[S1<<m|S2]);
for(ui i=0;x<=N&&i<=k[id];x*=p[id],++i)DFS(id+1,S1|(i==k[id])<<id,S2|(i==0)<<id,x);
}
inline void Divide(ui N){
for(ui i=2;i*i<=N;++i)if(!(N%i)){
p[m]=i;while(!(N%i))++k[m],N/=i;++m;
}
if(N^1)p[m]=N,k[m]=1,++m;
for(ui i=m-1;~i;--i){
x[i]=1./p[i]+1e-15;t[i]=y[i]=1;for(ui j=1;j<=k[i];++j)y[i]*=x[i],t[i]*=p[i];
}
}
inline ui read(){
ui n(0);char s;while(!isdigit(s=*_P1++));while(n=n*10+(s&15),isdigit(s=*_P1++));return n;
}
inline void write(ui n){
static char s[10];ui top(0);while(s[++top]=n%10^48,n/=10);while(*_P2++=s[top],--top);*_P2++=10;
}
signed main(){
fread(_INPUT,1,1<<21,stdin);
N=read();G=read();L=read();Q=read();invG=1./G+1e-15;
if(L%G){
while(Q--)putchar(48),putchar(10);return 0;
}
N*=invG;L*=invG;Divide(L);DFS(0,0,0,1);pw2[0]=1;for(ui i=1;i^1024;++i)pw2[i]=2*pw2[i-1]%mod;
const ui&M=1<<m*2;
for(ui len=1;len^M;len<<=1)for(ui k=0;k^M;k+=len<<1)for(ui i=0;i^len;++i)f[i|k|len]+=f[i|k];
for(ui S=0;S^M;++S)f[S]&&--f[S],f[S]=S&&(ppc[S]=ppc[S>>1]^(S&1))?mod-pw2[f[S]]:pw2[f[S]];
for(ui len=1;len^M;len<<=1)for(ui k=0;k^M;k+=len<<1)for(ui i=0;i^len;++i)f[i|k]=(f[i|k]+f[i|k|len])%mod;
while(Q--){
X=read();
if(ui(X*invG)*G^X){
*_P2++=48;*_P2++=10;continue;
}
if(X*=invG,L%X||X>N){
*_P2++=48;*_P2++=10;continue;
}
ui S1(0),S2(0);
for(ui i=0;i^m;++i)S1|=(ui(X*y[i])*t[i]==X)<<i,S2|=(ui(X*x[i])*p[i]!=X)<<i;
write(f[S1<<m|S2]);continue;
}
fwrite(_OUTPUT,1,_P2-_OUTPUT,stdout);
}