zoukankan      html  css  js  c++  java
  • luogu P5289 [十二省联考2019]皮配

    传送门

    首先考虑一个正常的dp,设(f_{i,j,k})为前(i)个学校,(j)人在(color{#0000FF}{蓝阵营}),(k)人在(color{#654321}{吔})派系的方案,转移枚举选哪个导师就好了,注意一个城市要选同一阵营,所以可以多开一维(0/1)表示当前城市在哪个阵营

    (k=0)的情况,可以发现选阵营和选派系是可以独立考虑的,因为一个学校在选择同一派系的情况下,这个学校选择哪个阵营对于两个派系的人数没有影响,一个城市选择同一阵营的情况下,里面的学校怎么选派系对于两个阵营总人数没有影响.那就可以dp出(g_{i,j})为前(i)个城市(j)人在(color{#0000FF}{蓝阵营})的方案,以及(h_{i,k})为前(i)个学校,(k)人在(color{#654321}{吔})派系的方案,然后两者之和的乘积就是答案

    (kle 30)的情况,一个显然的想法是把所有有限制学校的城市单独拿出来做(f)数组的dp,然后其他的做(g)(h)的dp,然后方案拼起来.至于拼起来,就是枚举(f)(j)(k),然后(g)(h)的下标就会限制在一个区间内,前缀和即可

    只不过可能这些城市的学校贼多,,,不过可以发现那些城市的没限制学校还是可以乱选派系的,所以可以把选派系的贡献算到(h)里,至于这些学校的选择阵营贡献算在(f)里.具体说就是把(f_{i,j,k})改为前(i)个有限制学校城市的学校,(j)人在(color{#0000FF}{蓝阵营}),限制学校(k)人在(color{#654321}{吔})派系的方案,然后转移是碰到无限制学校就转移(h),否则转移(f)

    // luogu-judger-enable-o2
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<map>
    #include<set>
    #define LL long long
    #define db double
    
    using namespace std;
    const int N=2500+10,M=300+10,mod=998244353;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}
    int f[2][2][N][M],g[2][N],h[2][N];
    int n,c,c0,c1,d0,d1,kk,m;
    bool ht[N];
    struct sch
    {
        int b,s,m;
        bool operator < (const sch &bb) const {return ht[b]!=ht[bb.b]?ht[b]<ht[bb.b]:b<bb.b;}
    }a[N];
    
    int main()
    {
        int T=rd();
        while(T--)
        {
            memset(f,0,sizeof(f));
            memset(g,0,sizeof(g));
            memset(h,0,sizeof(h));
            n=rd(),c=rd();
            for(int i=1;i<=c;++i) ht[i]=0;
            c0=rd(),c1=rd(),d0=rd(),d1=rd();
            for(int i=1;i<=n;++i) a[i].b=rd(),a[i].s=rd(),a[i].m=-1;
            kk=rd();
            for(int i=1;i<=kk;++i)
            {
                int x=rd(),y=rd();
                ht[a[x].b]=1,a[x].m=y;
            }
            sort(a+1,a+n+1);
            int m=n;
            while(m&&ht[a[m].b]) --m;
            int nw=1,la=0;
            g[la][0]=1;
            for(int i=1,sm=0,sb=0;i<=m;++i)
            {
                sm+=a[i].s,sb+=a[i].s;
                if(i<m&&a[i].b==a[i+1].b) continue;
                for(int j=max(sm-sb-c1,0);j<=sm-sb&&j<=c0;++j)
                {
                    if(!g[la][j]) continue;
                    if(j+sb<=c0) ad(g[nw][j+sb],g[la][j]);
                    if(sm-j<=c1) ad(g[nw][j],g[la][j]);
                }
                memset(g[la],0,sizeof(int)*(c0+3));
                sb=0;
                nw^=1,la^=1;
            }
            int lg=la;
            nw=1,la=0;
            h[la][0]=1;
            for(int i=1,sm=0;i<=m;++i)
            {
                sm+=a[i].s;
                for(int j=max(sm-a[i].s-d1,0);j<=sm-a[i].s&&j<=d0;++j)
                {
                    if(!h[la][j]) continue;
                    if(j+a[i].s<=d0) ad(h[nw][j+a[i].s],h[la][j]);
                    if(sm-j<=d1) ad(h[nw][j],h[la][j]);
                }
                memset(h[la],0,sizeof(int)*(d0+3));
                nw^=1,la^=1;
            }
            int lh=la,nh=nw,sk=0,sum=0,ans=0;
            for(int i=1;i<=m;++i) sum+=a[i].s;
            nw=1,la=0;
            f[la][0][0][0]=1;
            for(int i=m+1,sm=0;i<=n;++i)
            {
                bool fg=0;
                sm+=a[i].s;
                if(i==m+1||a[i].b!=a[i-1].b)
                {
                    for(int j=0;j<=c0;++j)
                        for(int k=0;k<=sk;++k)
                            f[la][0][j][k]=f[la][1][j][k]=(f[la][0][j][k]+f[la][1][j][k])%mod;
                }
                if(~a[i].m)
                {
                    sk+=a[i].s;
                    for(int j=max(sm-a[i].s-c1,0);j<=sm-a[i].s&&j<=c0;++j)
                        for(int k=0;k<=sk;++k)
                        {
                            if(f[la][0][j][k])
                            {
                                if(a[i].m!=0&&j+a[i].s<=c0) ad(f[nw][0][j+a[i].s][k+a[i].s],f[la][0][j][k]);
                                if(a[i].m!=1&&j+a[i].s<=c0) ad(f[nw][0][j+a[i].s][k],f[la][0][j][k]);
                            }
                            if(f[la][1][j][k])
                            {
                                if(a[i].m!=2&&sm-j<=c1) ad(f[nw][1][j][k+a[i].s],f[la][1][j][k]);
                                if(a[i].m!=3&&sm-j<=c1) ad(f[nw][1][j][k],f[la][1][j][k]);
                            }
                        }
                }
                else
                {
                    for(int j=max(sm-a[i].s-c1,0);j<=sm-a[i].s&&j<=c0;++j)
                        for(int k=0;k<=sk;++k)
                        {
                            if(f[la][0][j][k]&&j+a[i].s<=c0) ad(f[nw][0][j+a[i].s][k],f[la][0][j][k]);
                            if(f[la][1][j][k]&&sm-j<=c1) ad(f[nw][1][j][k],f[la][1][j][k]);
                        }
                    for(int j=max(sum+sm-sk-a[i].s-d1,0);j<=sum+sm-sk&&j<=d0;++j)
                    {
                        if(!h[lh][j]) continue;
                        if(j+a[i].s<=d0) ad(h[nh][j+a[i].s],h[lh][j]);
                        if(sum+sm-sk-j<=d1) ad(h[nh][j],h[lh][j]);
                    }
                    fg=1;
                }
                for(int j=0;j<=c0;++j)
                    for(int k=0;k<=sk;++k)
                        f[la][0][j][k]=f[la][1][j][k]=0;
                nw^=1,la^=1;
                if(fg)
                {
                    memset(h[lh],0,sizeof(int)*(d0+3));
                    nh^=1,lh^=1;
                }
            }
            for(int j=1;j<=c0;++j) ad(g[lg][j],g[lg][j-1]);
            for(int j=1;j<=d0;++j) ad(h[lh][j],h[lh][j-1]);
            for(int i=m+1;i<=n;++i) sum+=a[i].s;
            for(int j=0;j<=c0;++j)
                for(int k=0;k<=sk;++k)
                {
                    if((f[la][0][j][k]+f[la][1][j][k])%mod==0) continue;
                    int l1=max(sum-j-c1,0),r1=min(sum,c0)-j,l2=max(sum-k-d1,0),r2=min(sum,d0)-k;
                    if(l1<=r1&&l2<=r2)
                    {
                        int gg=(g[lg][r1]-(l1?g[lg][l1-1]:0)+mod)%mod,hh=(h[lh][r2]-(l2?h[lh][l2-1]:0)+mod)%mod;
                        ans=(ans+1ll*(f[la][0][j][k]+f[la][1][j][k])%mod*gg%mod*hh%mod)%mod;
                    }
                }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Java中net.sf.json包关于JSON与对象互转的坑
    Java IO(1)基础知识——字节与字符
    [Github]给已创建的GitHub项目添加LICENSE
    [MAC]激活Sublime Text
    [MAC]安装配置Charles
    [iOS]15个iOS视频播放控件
    [iOS]UIWindow详解
    [Swift]LeetCode1320. 二指输入的的最小距离 | Minimum Distance to Type a Word Using Two Fingers
    [Swift]LeetCode1319. 连通网络的操作次数 | Number of Operations to Make Network Connected
    [Swift]LeetCode1318. 或运算的最小翻转次数 | Minimum Flips to Make a OR b Equal to c
  • 原文地址:https://www.cnblogs.com/smyjr/p/10713772.html
Copyright © 2011-2022 走看看