Luogu5289 [十二省联考2019]皮配

Luogu5289 [十二省联考2019]皮配

背包

对于没有偏好的学校,可以发现城市选阵营、学校选派系是没有关系的。因此我们可以用两次背包求出两类答案再进行合并。

考虑对于有限制的学校单独\(dp\)

\(F_{i,j}\)表示当前城市在蓝阵营,蓝阵营中有\(i\)人(不包括当前城市),且有\(j\)个人在鸭派系的方案数。

\(G_{i,j}\)表示当前城市在红阵营,蓝阵营中有\(i\)人(不包括当前城市),且有\(j\)个人在鸭派系的方案数。

\(dp_{i,j,k}\)表示前\(i\)个有限制的学校,有\(j\)人在蓝阵营,\(k\)人在鸭派系的方案数。

然后两个背包合并,预处理前缀和。

如果一个学校没有偏好,但是该城市存在学校有偏好,依然不影响答案,因为这时候学校只负责选择派系,阵营会由\(dp\)数组计算,没有偏好的学校的阵营直接与城市一致即可。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 1005
#define M 2505
#define ll long long
using namespace std;
const int p=998244353;
struct modint
{
    int x;
    modint (int xx=0)
    {
        x=xx;
    }
    modint operator + (modint A)
    {
        return modint((x+A.x)%p);
    }
    modint operator + (int A)
    {
        return modint((x+A)%p);
    }
    modint operator - (modint A)
    {
        return modint((x-A.x)%p);
    }
    modint operator - (int A)
    {
        return modint((x-A)%p);
    }
    modint operator * (modint A)
    {
        return modint((ll)x*A.x%p);
    }
    modint operator * (int A)
    {
        return modint((ll)x*A%p);
    }
    void operator += (modint A)
    {
        (*this)=(*this)+A;
    }
    void operator *= (modint A)
    {
        (*this)=(*this)*A;
    }
    void operator += (int A)
    {
        (*this)=(*this)+A;
    }
    void operator *= (int A)
    {
        (*this)=(*this)*A;
    }
    void setNum(int t)
    {
        x=t;
    }
    void read()
    {
        scanf("%d",&x);
    }
    void print()
    {
        x=(x%p+p)%p;
        printf("%d\n",x);
    }
}f[M],g[M],F[M][M],G[M][M],dp[M][M];
int T,n,c,k,x,y,c0,c1,d0,d1,mx,my,s0;
int bel[N],s[N],cit[N];
int hate[N];
bool hat[N];
modint calc(int a,int b)
{
    int L1=max(s0-c1-a,0),R1=c0-a,L2=max(s0-d1-b,0),R2=d0-b;
    if (L1>R1 || L2>R2)
        return 0;
    return (f[R1]-f[L1-1])*(g[R2]-g[L2-1]);
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&c);
        memset(cit,0,(c+1)*sizeof(int)),s0=0;
        scanf("%d%d%d%d",&c0,&c1,&d0,&d1);
        for (int i=1;i<=n;++i)
            scanf("%d%d",&bel[i],&s[i]),cit[bel[i]]+=s[i],s0+=s[i];
        memset(hate,-1,(n+1)*sizeof(int));
        memset(hat,false,(c+1)*sizeof(bool));
        scanf("%d",&k);
        for (int i=1;i<=k;++i)
        {
            scanf("%d%d",&x,&y);
            hate[x]=y,hat[bel[x]]=true;
        }
        memset(f,0,(c0+1)*sizeof(modint));
        f[0]=1;
        for (int i=1;i<=c;++i)
        {
            if (!cit[i] || hat[i])
                continue;
            for (int j=c0;j>=cit[i];--j)
                f[j]+=f[j-cit[i]];
        }
        memset(g,0,(d0+1)*sizeof(modint));
        g[0]=1;
        for (int i=1;i<=n;++i)
        {
            if (~hate[i])
                continue;
            for (int j=d0;j>=s[i];--j)
                g[j]+=g[j-s[i]];
        }
        for (int i=0;i<=c0;++i)
            for (int j=0;j<=d0;++j)
                dp[i][j]=F[i][j]=G[i][j]=0;
        mx=my=0;
        dp[0][0]=1;
        for (int i=1;i<=c;++i)
        {
            if (!hat[i])
                continue;
            for (int j=0;j<=mx;++j)
                for (int k=0;k<=my;++k)
                    F[j][k]=G[j][k]=dp[j][k];
            for (int j=1;j<=n;++j)
            {
                if (!~hate[j] || bel[j]!=i)
                    continue;
                my=min(d0,my+s[j]);
                for (int A=mx;A>=0;--A)
                    for (int B=my;B>=0;--B)
                        F[A][B]=((B>=s[j] && hate[j]!=0)?F[A][B-s[j]]:0)+((hate[j]!=1)?F[A][B]:0),
                        G[A][B]=((B>=s[j] && hate[j]!=2)?G[A][B-s[j]]:0)+((hate[j]!=3)?G[A][B]:0);
            }
            mx=min(c0,mx+cit[i]);
            for (int j=0;j<=mx;++j)
                for (int k=0;k<=my;++k)
                    dp[j][k]=((j>=cit[i])?F[j-cit[i]][k]:0)+G[j][k];
        }
        for (int i=1;i<=c0;++i)
            f[i]+=f[i-1];
        for (int i=1;i<=d0;++i)
            g[i]+=g[i-1];
        modint ans;
        for (int i=0;i<=mx;++i)
            for (int j=0;j<=my;++j)
                ans+=dp[i][j]*calc(i,j);
        ans.print();
    }
    return 0;
}
posted @ 2020-12-01 08:06  GK0328  阅读(74)  评论(0编辑  收藏  举报