[子集卷积] 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;
}
posted @ 2020-08-12 14:50  AE酱  阅读(241)  评论(0编辑  收藏  举报