bzoj 5498: [2019省队联测]皮配dp

Posted lokiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 5498: [2019省队联测]皮配dp相关的知识,希望对你有一定的参考价值。

是个神仙dp……
参考:https://www.luogu.org/blog/xzz-233/solution-p5289
设f[i][j][k]是前i个有限制的城市,所有学校中选蓝色阵营有j人,有限制的学校中鸭派系有k人的方案数;g[i][j]是前i个没有限制的城市,蓝色阵营有j人的方案数;h[i][j]是前i个没有限制的学校,鸭派系有j人的方案数
f的转移枚举当前阵营
全dp出来之后,把gh前缀和处理,然后一段一段的和f合并加到ans上

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2505,mod=998244353;
int T,n,c,c0,c1,d0,d1,k,m,ss,ans,b[N],s[N],f[N][N],f1[N][N],f2[N][N],g[N],h[N],ki[N],kp[N],v[N],ct[N],sum[N],sm[N];
vector<int>sc[N];
void jia(int &x,int y)
{
    if((x+=y)>=mod)
        x-=mod;
}
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    T=read();
    while(T--)
    {
        memset(f,0,sizeof(f));
        memset(f1,0,sizeof(f1));
        memset(f2,0,sizeof(f2));
        memset(g,0,sizeof(g));
        memset(h,0,sizeof(h));
        memset(sm,0,sizeof(sm));
        memset(sum,0,sizeof(sum));
        memset(ct,0,sizeof(ct));
        for(int i=0;i<N;i++)
            sc[i].clear();
        ss=0,ans=0;
        n=read(),c=read(),c0=read(),c1=read(),d0=read(),d1=read();
        for(int i=1;i<=n;i++)
            b[i]=read(),s[i]=read(),sum[b[i]]+=s[i],ss+=s[i];
        m=k=read();
        for(int i=1;i<=n;i++)
            v[i]=-1;
        for(int i=1;i<=k;i++)
        {
            ki[i]=read(),kp[i]=read();
            ct[i]=b[ki[i]];
            sc[b[ki[i]]].push_back(ki[i]);
            v[ki[i]]=kp[i];
        }
        sort(ct+1,ct+1+m);
        m=unique(ct+1,ct+1+m)-ct-1;
        for(int i=1;i<=n;i++)
            if(v[i]!=-1)
                sm[b[i]]+=s[i];
        f[0][0]=1;
        for(int i=1,s1=0,s2=0;i<=m;i++)
        {
            s1=min(c0,s1+sum[ct[i]]),s2=min(d0,s2+sm[ct[i]]);
            for(int o=0;o<=1;o++)
            {
                for(int j=0;j<=s1;j++)
                    for(int k=0;k<=s2;k++)
                        f1[j][k]=f[j][k];
                for(int l=0,len=sc[ct[i]].size();l<len;l++)
                {
                    int x=sc[ct[i]][l];
                    for(int j=s1;j>=0;j--)
                        for(int k=s2;k>=0;k--)
                        {
                            if(o==0)
                            {
                                f1[j][k]=0;
                                if(v[x]!=1&&j>=s[x])
                                    jia(f1[j][k],f1[j-s[x]][k]);
                                if(v[x]!=0&&j>=s[x]&&k>=s[x])
                                    jia(f1[j][k],f1[j-s[x]][k-s[x]]);
                            }
                            else
                            {
                                if(v[x]==3)
                                    f1[j][k]=0;
                                if(v[x]!=2&&k>=s[x])
                                    jia(f1[j][k],f1[j][k-s[x]]);
                            }
                        }
                }
                if(o==0)
                {
                    int nw=sum[ct[i]]-sm[ct[i]];
                    for(int j=s1;j>=0;j--)
                        for(int k=s2;k>=0;k--)
                        {
                            if(j>=nw)
                                f1[j][k]=f1[j-nw][k];
                            else
                                f1[j][k]=0;
                        }
                    for(int j=0;j<=s1;j++)
                        for(int k=0;k<=s2;k++)
                            f2[j][k]=f1[j][k];
                }
                else
                {
                    for(int j=0;j<=s1;j++)
                        for(int k=0;k<=s2;k++)
                            f[j][k]=(f1[j][k]+f2[j][k])%mod;
                }
            }
        }
        g[0]=1;
        for(int i=1,smm=0;i<=c;i++)
            if(sc[i].empty()&&sum[i])
            {
                smm=min(c0,smm+sum[i]);
                for(int j=smm;j>=0;j--)
                    if(j>=sum[i])
                        jia(g[j],g[j-sum[i]]);
            }
        h[0]=1;
        for(int i=1,smm=0;i<=n;i++)
            if(v[i]==-1)
            {
                smm=min(d0,smm+s[i]);
                for(int j=smm;j>=0;j--)
                    if(j>=s[i])
                        jia(h[j],h[j-s[i]]);
            }
        for(int i=1;i<=c0;i++)
            jia(g[i],g[i-1]);
        for(int i=1;i<=d0;i++)
            jia(h[i],h[i-1]);
        for(int i=0;i<=c0;i++)
            if(ss-i-c1-1<c0-i)
                for(int j=0;j<=d0;j++)
                    if(ss-j-d1-1<d0-j)
                        jia(ans,1ll*f[i][j]*(g[c0-i]-(ss-i-c1-1>=0?g[ss-i-c1-1]:0)+mod)%mod*(h[d0-j]-(ss-j-d1-1>=0?h[ss-j-d1-1]:0)+mod)%mod);
        printf("%d
",(ans+mod)%mod);
    }
    return 0;
}

以上是关于bzoj 5498: [2019省队联测]皮配dp的主要内容,如果未能解决你的问题,请参考以下文章

bzoj5252: [2018多省省队联测]林克卡特树

bzoj 5499: [2019省队联测]春节十二响堆

bzoj 5496: [2019省队联测]字符串问题SAM+拓扑

bzoj 5249 [2018多省省队联测] IIIDX

[bzoj5249][2018多省省队联测]IIIDX

BZOJ 5248: [2018多省省队联测]一双木棋