题解:CF1728G Illumination
先考虑除了询问那个点以外其它点的贡献。
考虑把 哈集幂集合幂级数的形式,把乘法定义成或卷积,令第
注意到
考虑把有值的位置相同的那些
对于同一种,因为每次新加入的集合都是之前集合的超集,只要把所有有值的位置扫一遍就可以得出两者的或卷积。
处理完每一种的贡献之后,把不同种类用 FWT 求或卷积,设
现在考虑对于一个询问,新加入的这个灯笼的集合幂级数也只有
时间复杂度
::::info[Code]
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
const int N=5e5+10,mod=998244353;
inline int add(int a,int b){return ((a+=b)>=mod)?(a-mod):a;}
inline int norm(int a,int b){return ((a-=b)<0)?(a+mod):a;}
int d,n,m,qwq,a[N],p[30],id[30],val[N],s[N],cnt;
mt19937_64 rnd(time(0));
const ull pp=13331;
ull pri[(1<<16)+5];
map<ull,int>mp;
vector<int>f[270];
inline void fwt_OR(vector<int>&f,int opt){
int limit=f.size();
for(int len=2;len<=limit;len<<=1)
for(int i=0;i+len-1<limit;i+=len)
for(int j=i+(len>>1);j<i+len;++j)
f[j]=add(f[j],f[j-(len>>1)]*opt%mod);
}
inline void fwt_AND(vector<int>&f){
int limit=f.size();
for(int len=2;len<=limit;len<<=1)
for(int i=0;i+len-1<limit;i+=len)
for(int j=i;j<i+(len>>1);++j)
f[j]=add(f[j],f[j+(len>>1)]);
}
signed main(){
cin>>d>>n>>m;
for(int i=0;i<(1<<m);++i)pri[i]=rnd();
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=m;++i){
cin>>p[i];
id[i]=i;
}
for(int i=1;i<=n;++i){
sort(id+1,id+1+m,[&](int x,int y){return abs(a[i]-p[x])<abs(a[i]-p[y]);});
val[0]=abs(a[i]-p[id[1]]),s[0]=0;
ull hash=0;
for(int j=1;j<=m;++j){
s[j]=s[j-1]|(1<<(id[j]-1));
hash=hash*pp+pri[s[j]];
if(j==m)val[j]=d-abs(a[i]-p[id[j]])+1;
else val[j]=abs(a[i]-p[id[j+1]])-abs(a[i]-p[id[j]]);
}
if(mp.find(hash)==mp.end()){
mp[hash]=++cnt;
f[cnt].resize(1<<m);
f[cnt][0]=1;
}
int sum1=0,sum2=0,pos=mp[hash];
for(int j=0;j<=m;++j){
int last=f[pos][s[j]];
f[pos][s[j]]=add(last*sum2%mod,add(sum1*val[j]%mod,last*val[j]%mod));
sum1=add(sum1,last);
sum2=add(sum2,val[j]);
}
}
int limit=(1<<m);
f[0].resize(limit);
for(int i=0;i<limit;++i)f[0][i]=1;
for(int i=1;i<=cnt;++i){
fwt_OR(f[i],1);
for(int j=0;j<limit;++j)
f[0][j]=f[0][j]*f[i][j]%mod;
}
fwt_OR(f[0],mod-1);
fwt_AND(f[0]);
cin>>qwq;
int pos;
while(qwq--){
cin>>pos;
sort(id+1,id+1+m,[&](int x,int y){return abs(pos-p[x])<abs(pos-p[y]);});
val[0]=abs(pos-p[id[1]]),s[0]=0;
for(int j=1;j<=m;++j){
s[j]=s[j-1]|(1<<(id[j]-1));
if(j==m)val[j]=d-abs(pos-p[id[j]])+1;
else val[j]=abs(pos-p[id[j+1]])-abs(pos-p[id[j]]);
}
int ans=0;
for(int i=0;i<=m;++i)ans=add(ans,val[i]*f[0][(limit-1)^s[i]]%mod);
cout<<ans<<"\n";
}
return 0;
}
::::