luogu P5289 [十二省联考2019]皮配

Posted smyjr

tags:

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

传送门

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

(k=0)的情况,可以发现选(color{#654321}{吔})派系的(Yazid)(Zayid)都会增加(color{#654321}{吔})派系人数,另一个派系亦然,所以选阵营和选派系是相对独立的,所以可以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),然后其他城市的维度就会限制在一个范围内,就是区间和乘起来,可以前缀和求.

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

// 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;
}

以上是关于luogu P5289 [十二省联考2019]皮配的主要内容,如果未能解决你的问题,请参考以下文章

luogu P5285 [十二省联考2019]骗分过样例

luogu P5284 [十二省联考2019]字符串问题

Luogu P5284 [十二省联考2019]字符串问题

题解Luogu P5283 [十二省联考2019]异或粽子

[十二省联考2019]异或粽子(可持久化tire,堆)

[十二省联考2019] 异或粽子 解题报告 (可持久化Trie+堆)