啊啊啊边界判错了搞死我了QAQ

这题是一个想起来很休闲写起来很恶心的背包

对于\(k=0\)的情况,可以发现选阵营和选派系是独立的,对选城市选阵营和学校选派系分别跑一遍01背包就行了

对于\(k>0\)的情况,设\(f[i][0/1][j][k]\)表示对于第\(i\)个有限制的学校,该学校选择\(0/1\)阵营时,\(C0\)阵营有\(j\)人,\(D0\)派系有\(k\)人的方案数

转移要分类讨论,有点麻烦,看代码吧

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define N 1010
#define M 2505
#define R register
#define rep(i,x,y) for(i=x;i<=y;++i)
#define des(i,x,y) for(i=x;i>=y;--i)
#define mod 998244353
using namespace std;

int f[2][2][M][M],pref0[M],preg0[M],f0[M],g0[M];
int C0,C1,D0,D1,c0[N],tmp2[N],sum2=0;
int cnts[2],cntc[2],n,c;
bool visct[N]; 

inline int add(int x,int y){ return (x+y>=mod)?x+y-mod:x+y; }
inline int sub(int x,int y){ return (x-y<0)?x-y+mod:x-y; }
struct hhw{ int b,s,id,lim; } tmp[N],a0[N],ak[N];
inline void rd(int &x){
    char c=getchar();R int y=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0' && c<='9') y=y*10+c-'0',c=getchar();
    x=y;
}
inline void solve0(){
    R int i,j;
    f0[0]=pref0[0]=1;
    rep(i,1,cntc[0])
        des(j,C0-c0[i],0)
            f0[j+c0[i]]=add(f0[j+c0[i]],f0[j]);
    rep(i,1,C0) pref0[i]=add(pref0[i-1],f0[i]);
    g0[0]=preg0[0]=1;
    rep(i,1,cnts[0])
        des(j,D0-a0[i].s,0)
            g0[j+a0[i].s]=add(g0[j+a0[i].s],g0[j]);
    rep(i,1,D0) preg0[i]=add(preg0[i-1],g0[i]);
}

inline bool cmp(const hhw &x,const hhw &y){ return x.b<y.b; }

inline void addf(int a,int b,int c,int d,int x){
    if(c>C0||d>D0) return;
    f[a][b][c][d]=add(f[a][b][c][d],x);
}

inline void solvek(){
    f[0][0][0][0]=1;
    R int i,j,k,o,pos=1;
    sort(ak+1,ak+cnts[1]+1,cmp);
    rep(i,1,cnts[1]){
        rep(o,0,1)
            des(j,C0,0)
                des(k,sum2,0){//不能直接写D0!!!要把有限制的学校的人数统计出来!!!
                    f[pos][o][j][k]=0;
                    if(o==0){
                        if(ak[i].lim^0){
                            if(ak[i].b==ak[i-1].b)
                                addf(pos,o,j,k+ak[i].s,f[pos^1][o][j][k]);
                            else{
                                addf(pos,o,j+tmp2[ak[i].b],k+ak[i].s,f[pos^1][o][j][k]);
                                addf(pos,o,j+tmp2[ak[i].b],k+ak[i].s,f[pos^1][o^1][j][k]);
                            }
                        }
                        if(ak[i].lim^1){
                            if(ak[i].b==ak[i-1].b)
                                addf(pos,o,j,k,f[pos^1][o][j][k]);
                            else{
                                addf(pos,o,j+tmp2[ak[i].b],k,f[pos^1][o][j][k]);
                                addf(pos,o,j+tmp2[ak[i].b],k,f[pos^1][o^1][j][k]);
                            }
                        }
                    } else{
                        if(ak[i].lim^2){
                            if(ak[i].b==ak[i-1].b)
                                addf(pos,o,j,k+ak[i].s,f[pos^1][o][j][k]);
                            else{
                                addf(pos,o,j,k+ak[i].s,f[pos^1][o][j][k]);
                                addf(pos,o,j,k+ak[i].s,f[pos^1][o^1][j][k]);
                            }
                        }
                        if(ak[i].lim^3){
                            if(ak[i].b==ak[i-1].b)
                                addf(pos,o,j,k,f[pos^1][o][j][k]);
                            else{
                                addf(pos,o,j,k,f[pos^1][o][j][k]);
                                addf(pos,o,j,k,f[pos^1][o^1][j][k]);
                            }
                        }
                    }
                }
        pos^=1;
    }
}

inline int qwq(int x,int y){ return y>=0?sub(pref0[x],pref0[y]):pref0[x]; }
inline int owo(int x,int y){ return y>=0?sub(preg0[x],preg0[y]):preg0[x]; }

inline void solve(){
    R int i,x,y,k,j,sum=0,ans=0;
    rd(n),rd(c);
    rd(C0),rd(C1),rd(D0),rd(D1);
    rep(i,1,n){
        rd(tmp[i].b),rd(tmp[i].s);
        tmp[i].id=i,tmp[i].lim=-1;
        sum+=tmp[i].s;
        tmp2[tmp[i].b]+=tmp[i].s;
    }
    rd(k);
    rep(i,1,k){
        rd(x),rd(y),tmp[x].lim=y;
        visct[tmp[x].b]=1;sum2+=tmp[x].s;
    }
    rep(i,1,n){
        if(tmp[i].lim==-1) a0[++cnts[0]]=tmp[i];
        else ak[++cnts[1]]=tmp[i];
    }
    rep(i,1,c){
        if(!visct[i] && tmp2[i]) c0[++cntc[0]]=tmp2[i];
        else cntc[1]++;
    }
    if(sum-C0>C1 || sum-D0>D1){
        printf("0\n");
        return;
    }
    solve0(),solvek();
    rep(i,0,C0)
        rep(j,0,D0){
            if(sum-C1-i<=C0-i && sum-D1-j<=D0-j){
                int x=add(f[cnts[1]&1][0][i][j],f[cnts[1]&1][1][i][j]);
                ans=add(ans,1ll*x*qwq(C0-i,sum-C1-i-1)%mod*owo(D0-j,sum-D1-j-1)%mod);
            }
            f[0][0][i][j]=f[0][1][i][j]=f[1][0][i][j]=f[1][1][i][j]=0;
        }
    printf("%d\n",ans);
    rep(i,1,c) tmp2[i]=visct[i]=0;
    cntc[1]=cntc[0]=cnts[1]=cnts[0]=sum=sum2=0;
    memset(f0,0,sizeof(int)*(C0+1));
    memset(g0,0,sizeof(int)*(D0+1));
}

int main(){
    R int t;rd(t);
    while(t--) solve();
}

洛谷P5289 [十二省联考2019]皮配(01背包)的更多相关文章

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

    传送门 首先考虑一个正常的dp,设\(f_{i,j,k}\)为前\(i\)个学校,\(j\)人在\(\color{#0000FF}{蓝阵营}\),\(k\)人在\(\color{#654321}{吔} ...

  2. luogu P5289 [十二省联考2019]皮配 背包

    LINK:皮配 我承认是一道很难的题目. 不过对于这道题 部分分的提示显得尤为重要. 首先是 40分的暴力dp 很容易想 但是不容易写. 从40分可以发现我们只需要把蓝阵营和鸭派系的人数给存在起来就行 ...

  3. 【BZOJ5498】[十二省联考2019]皮配(动态规划)

    [BZOJ5498][十二省联考2019]皮配(动态规划) 题面 BZOJ 洛谷 题解 先考虑暴力\(dp\),设\(f[i][j][k]\)表示前\(i\)所学校,有\(j\)人在某个阵营,有\(k ...

  4. 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)

    LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...

  5. 洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)

    LOJ 洛谷 考场上都拍上了,8:50才发现我读错了题=-= 两天都读错题...醉惹... \(Solution1\) 先求一遍前缀异或和. 假设左端点是\(i\),那么我们要在\([i,n]\)中找 ...

  6. 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]

    传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...

  7. 洛谷 5291 [十二省联考2019]希望(52分)——思路+树形DP

    题目:https://www.luogu.org/problemnew/show/P5291 考场上写了 16 分的.不过只得了 4 分. 对于一个救援范围,其中合法的点集也是一个连通块. 2n 枚举 ...

  8. 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)

    题面 传送门 题解 首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\).我们发现一个节点的后缀是它的所有祖先 那么我们是不是直接按着\(parent\)树建边就可以了呢? 显然不是.我们假 ...

  9. Luogu5289 十二省联考2019皮配(动态规划)

    将选择导师看成先选阵营再选派系,这样有显然的O(nm2)暴力,即按城市排序后,设f[i][j][k]为前i个学校中第一个阵营有j人第一个派系有k人的方案数,暴力背包. 对于k=0,可以发现选阵营和选派 ...

随机推荐

  1. java爬虫系列第二讲-爬取最新动作电影《海王》迅雷下载地址

    1. 目标 使用webmagic爬取动作电影列表信息 爬取电影<海王>详细信息[电影名称.电影迅雷下载地址列表] 2. 爬取最新动作片列表 获取电影列表页面数据来源地址 访问http:// ...

  2. Hibernate框架笔记02_主键生成策略_一级缓存_事务管理

    目录 0. 结构图 1. 持久化类的编写规则 1.1 持久化和持久化类 1.2 持久化类的编写规则 2. 主键生成策略 2.1 主键的分类 2.2 主键生成策略 3. 持久化类的三种状态[了解] 3. ...

  3. Flask实战第3天:url_for使用

    我们之前是通过url来找到对应的视图函数 /     =>    hello_world 那么url_for则是通过视图函数找到url hello world  =>  / 演示如下 #c ...

  4. mac webstorm无法打开 如何使webstorm不卡

    场景:在应用程序里删除了原先的webstorm,然后从官网下载了新的安装包,进行安装.安装后,webstorm就再也打不开了. 解决方案:执行以下命令,清楚webstorm所有缓存,然后重新安装 $ ...

  5. OrmLite-更符合面向对象的数据库操作方式

    1. jar包下载 下载地址:http://ormlite.com/releases/,一般用core和android包即可. 如果使用的是android studio,也可以直接通过module s ...

  6. 链表倒数第k个节点

    1.一种较笨的办法是先将链表元素入栈,然后出栈找到倒数第k个节点值,再拿着值遍历链表去找到对于节点. 时间复杂度:O(n) (3n 遍历-出栈-遍历) 空间复杂度:O(n) (一个栈) 2.快慢指针, ...

  7. winserver-查看登陆日志

    Abstract 先要开启登陆审核,在查看登陆日志. 开启审核 运行 secpol.msc 日志查看 windowslog 下的security 管理员成功登陆后的eventid:4776,4648, ...

  8. Window10上安装Redis及其客户端

    资源下载地址 Redis安装包:https://github.com/MicrosoftArchive/redis/releases Redis客户端: 链接:https://pan.baidu.co ...

  9. Centos7上搭建redis主从

    1. 节点(服务器)数量说明 按照redis官方建议:salve和master的数量按照2n+1台服务器(1台master节点,2n台slave节点) 有兴趣的可以了解下redis的master选举机 ...

  10. HTML基础-------HTML标签(3)

    HTML标签(3) 表格 作用:制作一个表格 属性: 标签;table>tr>td(或者th) 语义; table:一个表格 tr:一行 td:一个单元格 th:单元格的表头 captio ...