[子集卷积] HDU 6851 Heart
题目大意
给定全集 \(S,|S|=21\),然后给出 \(n(1\leq n\leq 10^6)\) 个 \(S\) 的子集 \(P_i\),以及每个子集的价值 \(V_i\),再给出 \(m(1\leq m\leq 10^6)\) 个询问,每次询问一个 \(S\) 的一个子集 \(T\),求所有选取不相交子集组合出 \(T\) 的方案价值之和。若一种方案选取了 \(P_1,P_2,\dots,P_i\) 这些子集,则该方案的价值为 \(V_1\times V_2\times\dotsb\times V_i\)。
题解
按给出的子集二进制最高位分类,然后按二进制最高位从低到高依次进行子集卷积。
Code
自己写了下发现MLE:
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
#define bitcnt(x) __builtin_popcount(x)
const LL MOD=998244353LL;
const int maxn=(1<<22)+10;
int a[22][maxn],b[22][maxn],c[22][maxn];
int n,len;
void FMT(int *f,int n){
for(RG i=0;i<n;++i)
for(RG j=0;j<(1<<n);++j)
if(j&(1<<i)) f[j]=(f[j]+f[j^(1<<i)])%MOD;
}
void IFMT(int *f,int n){
for(RG i=0;i<n;++i)
for(RG j=0;j<(1<<n);++j)
if(j&(1<<i)) f[j]=((f[j]-f[j^(1<<i)])%MOD+MOD)%MOD;
}
void Convolution(int n){
for(RG x=0;x<=n;++x){
for(RG i=0;i<=x;++i)
for(RG s=0;s<(1<<n);++s)
c[x][s]=(1LL*c[x][s]+1LL*a[i][s]*b[x-i][s]%MOD)%MOD;
IFMT(c[x],n);
}
}
vector<pair<int,int> > Data[23];
int highbit(int x){
int p=1<<22,res=23;
while(!(p&x) && p){p>>=1;--res;}
return res;
}
void maintain(int h){
n=h;len=1<<n;
for(RG i=0;i<=n;++i){
fill(a[i],a[i]+len+5,0);
fill(b[i],b[i]+len+5,0);
}
b[0][0]=1;
for(RG i=0;i<(int)Data[h].size();++i){
int p=Data[h][i].second;
int x=Data[h][i].first;
b[bitcnt(p)][p]=(b[bitcnt(p)][p]+x)%MOD;
}
for(RG i=0;i<len;++i){
int x=c[bitcnt(i)][i];
a[bitcnt(i)][i]=x;
}
a[0][0]=1;
for(RG i=0;i<=n;++i)
fill(c[i],c[i]+len+5,0);
for(RG i=0;i<=n;++i){
FMT(a[i],n);
FMT(b[i],n);
}
Convolution(n);
}
int main(){
int Num;Read(Num);
int highest=0;
for(RG i=1;i<=Num;++i){
int x,p,h;Read(x);Read(p);
h=highbit(p);highest=max(highest,h);
Data[h].push_back(make_pair(x,p));
}
for(int step=0;step<=highest;++step)
maintain(step);
int QNum;Read(QNum);
int Case=10;
while(QNum--){
int x;Read(x);
printf("%d\n",c[bitcnt(x)][x]);
}
return 0;
}
然后抄袭了下std:
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
namespace FMT{
#define bitcnt(x) __builtin_popcount(x)
const int MOD=998244353LL;
const int Base=21;
inline int mo(int x){
if(x>=MOD) x-=MOD;
if(x<0) x+=MOD;
return x;
}
inline int mul(int x,int y){return 1LL*x*y%MOD;}
void FMT(vector<int> &f,int n=Base){
int len=1<<n;
for(RG i=0;i<n;++i)
for(RG j=0;j<len;++j)
if(j&(1<<i)) f[j]=mo(f[j]+f[j^(1<<i)]);
}
void IFMT(vector<int> &f,int n=Base){
int len=1<<n;
for(RG i=0;i<n;++i)
for(RG j=0;j<len;++j)
if(j&(1<<i)) f[j]=mo(f[j]-f[j^(1<<i)]);
}
vector<int> subset_convolution(vector<int> &A,vector<int> &B,int n=Base){
int len=1<<n;
vector<int> H(len);
vector<vector<int> > sH(n+1,vector<int>(len,0)),sA=sH,sB=sH;
for(RG s=0;s<len;++s){
sA[bitcnt(s)][s]=A[s];
sB[bitcnt(s)][s]=B[s];
}
for(RG i=0;i<=n;++i){
FMT(sA[i],n);
FMT(sB[i],n);
for(RG s=0;s<len;++s)
for(RG j=0;j<=i;++j)
sH[i][s]=mo(sH[i][s]+mul(sA[j][s],sB[i-j][s]));
IFMT(sH[i],n);
}
for(RG s=0;s<len;++s)
H[s]=sH[bitcnt(s)][s];
return H;
}
};
vector<int> Solve(const vector<int> &Data){
int Len=1<<21,base=21;
vector<int> Res(Len,0);
Res[0]=1;
for(int n=0;n<base;++n){
int len=1<<n;
auto A=vector<int>(Res.begin(),Res.begin()+len);
auto B=vector<int>(Data.begin()+len,Data.begin()+len*2);
auto C=FMT::subset_convolution(A,B,n);
for(RG i=len;i<(len<<1);++i)
Res[i]=C[i-len];
}
return Res;
}
int main(){
int Num,QNum;
vector<int> Data(1<<21,0);
Read(Num);
for(RG i=1;i<=Num;++i){
int x,p;Read(x);Read(p);
Data[p]=FMT::mo(Data[p]+x);
}
auto Ans=Solve(Data);
Read(QNum);
while(QNum--){
int x;Read(x);
printf("%d\n",Ans[x]);
}
return 0;
}