「十二省联考 2019」皮配——dp
题目
【题目描述】
#### 题目背景
一年一度的综艺节目《中国好码农》又开始了。本季度,好码农由 Yazid、Zayid、小 R、大 R 四位梦想导师坐镇,他们都将组建自己的梦想战队,并率领队员向梦想发起冲击。
四位导师的**派系**不尽相同,节目组为了营造看点,又将导师分成了不同的**阵营**,与此同时对不同阵营、不同派系都作出了战队总人数限制:
- 四位导师分成两个**阵营**:
- Yazid、小 R 两位导师组成**蓝阵营**,他们两位的战队人数**总和**不得超过 $C_0$。
- Zayid、大 R 两位导师组成**红阵营**,他们两位的战队人数**总和**不得超过 $C_1$。
- 四位导师分成两个**派系**:
- Yazid、Zayid 两位导师属于**鸭派系**,他们两位的战队人数**总和**不得超过 $D_0$。
- 小 R、大 R 两位导师属于 **R 派系**,他们两位的战队人数**总和**不得超过 $D_1$。
#### 题目描述
本季好码农邀请到了全国各路学生精英参赛。他们来自全国 $c$ 个城市的 $n$ 所不同学校(城市的编号从 $1$ 至 $c$,学校的编号从 $1$ 至 $n$)。其中,第 $i$ 所学校所属的城市编号为 $b_i$,且共有 $s_i$ 名选手参赛。
在「题目背景」中提到的各总人数限制之外,本季度《中国好码农》的导师选择阶段有额外规则如下:
- 来自同**城市**的所有选手必须加入相同的**阵营**。
- 来自同**学校**的所有选手必须选择相同的**导师**。
对于导师,大部分学校的学生对导师没有**偏好**。但是有 $k$ 所学校,其中每所学校的学生有且仅有一位他们不喜欢的导师。同一所学校的学生不喜欢的导师相同,他们**不会加入他们不喜欢的导师的战队**。
面对琳琅满目的规则和选手的偏好,作为好码农忠实观众的你想计算出,在所有选手都进行了战队选择后,战队组成共有多少种可能的局面?
- 两种战队组成的局面被认为是不同的,当且仅当在存在一所学校,使得在这两种局面中这所学校的选手加入了不同导师的战队。
- 由于答案可能很大,你只需输出可能局面数对 $998,244,353$ 取模的结果即可。
【输入格式】
从标准输入读入数据。
单个测试点中包含多组数据,输入的第一行包含一个非负整数 $T$ 表示数据组数。接下来依次描述每组数据,对于每组数据:
- 第 $1$ 行 $2$ 个正整数 $n,c$,分别表示学校数目、城市数目。
- 第 $2$ 行 $4$ 个正整数 $C_0,C_1,D_0,D_1$,分别表示题目中所描述的四个限制。
- 接下来 $n$ 行每行 $2$ 个正整数:
- 这部分中第 $i$ 行的两个数依次为 $b_i,s_i$,分别表示第 $i$ 所学校的所属城市以及选手数目。
- 保证 $b_i \leq c$,$s_i \leq \min\{M, 10\}$。其中 $M=\max{\left\{ C_0,C_1,D_0,D_1\right\}}$。
- 接下来 $1$ 行一个非负整数 $k$,表示选手有偏好的学校数目。
- 接下来 $k$ 行,每行 $2$ 个整数 $i,p$,描述编号为 $i$ 的学校选手有偏好:
- 其中,$p$ 为一个 $0$ 至 $3$ 之间的整数,描述该校选手不喜欢的导师:0 代表 Yazid,1 代表小 R,2 代表 Zayid,3 代表大 R。
- 保证 $1\leq i\leq n$,且各行的 $i$ 互不相同。
对于输入的每一行,如果其包含多个数,则用单个空格将它们隔开。
【输出格式】
输出到标准输出。
依次输出每组数据的答案,对于每组数据:
- 一行一个整数,表示可能局面数对 $998,244,353$ 取模的结果。
【样例输入】
2
2 1
3 2 2 2
1 1
1 2
1
1 0
4 2
10 30 20 30
1 6
2 4
1 7
2 4
2
2 3
3 1
【样例输出】
1
22
【样例解释】
对于第 1 组数据:
- 唯一的城市 1 包含共 $3$ 名选手,但红阵营的总人数限制为 $2$,无法容纳这些选手,因此他们被迫只能选择蓝阵营。
- 在此基础上,由于 1 号学校的选手不喜欢 Yazid 老师,因此他们就必须加入 R 派系的小 R 老师麾下。
- 由于 R 派系总人数限制为 $2$,因此小 R 老师战队无法容纳 2 号学校的选手,所以他们只能被迫加入 Yazid 老师战队。
- 综上所述,可能的局面仅有这一种。
对于第 2 组数据:
- 一个显然的事实是,1 号城市的所有选手都无法加入蓝阵营,这是因为 1 号城市的选手总人数超过了蓝阵营的总人数限制,因此他们被迫全部加入红阵营。
- 对于 2 号城市选手加入蓝阵营的情况,稍加计算可得出共有 $15$ 种可能的局面。
- 对于 2 号城市选手加入红阵营的情况,稍加计算可得出共有 $7$ 种可能的局面。
- 综上所述,可能的局面数为 $15+7=22$ 种。
【数据范围与提示】
|测试点|$n$|$c$|$k$|$M$|
|:-:|:-:|:-:|:-:|:-:|
|$1$|$=1$|$=n$|$\le 1$|$=1$|
|$2$|$=10$|$=n$|$\le 10$|$\le 100$|
|$3$|$=20$|$=n$|$=0$|$\le 100$|
|$4$|$=30$|$=n$|$=0$|$\le 100$|
|$5$|$=30$|$=n$|$\le 30$|$\le 500$|
|$6$|$=500$|$=n$|$=0$|$\le 1000$|
|$7$|$=500$|$=30$|$= 30$|$\le 1000$|
|$8$|$=500$|$=n$|$= 30$|$\le 1000$|
|$9$|$=1000$|$=n$|$=0$|$\le 2500$|
|$10$|$=1000$|$=n$|$=30$|$\le 2500$|
其中,$M=\max{\left\{ C_0,C_1,D_0,D_1\right\}}$。
对于所有测试点,保证 $T\leq 5$。
对于所有测试点中的每一组数据,保证 $c\leq n\leq 1000$,$k\leq 30$,$M\leq 2500$,$1\leq s_i \leq \min\{M, 10\}$。
**另外,请你注意,数据并不保证所有的 $c$ 个城市都有参赛学校。**
#### 提示
十二省联考命题组温馨提醒您:
**数据千万条,清空第一条。**
**多测不清空,爆零两行泪。**
题解
这是一个 t1 难度 $ > $ t2 的故事
首先,是一个 $ 50 \% $ 的暴力
记 $ f[i][j][k] $ 表示前 $ i $ 个人,有 $ j $ 个在 $ 1 $ 阵营(蓝阵营,下同),有 $ k $ 个在 $ 1 $ 派系(鸭派系,下同)的方案数,然后随便转移,效率 $ O(nm^2) $
然后发现,如果没有限制的话,阵营和派系的人数是互不影响的,接着就可以根据这个搞事情
记 $ g1[i][j] $ 表示前 $ i $ 个城市(没有限制的),有 $ j $ 个在 $ 1 $ 阵营的方案数
$ g1[i][j]=g[i-1][j]+g[i-1][j-A[i]],A[i] $ 表示第 $ i $ 个城市的人数
记 $ g2[i][j] $ 表示前 $ i $ 个学校(没有限制的),有 $ j $ 个在 $ 1 $ 派系的方案数
$ g1[i][j]=g[i-1][j]+g[i-1][j-B[i]],B[i] $ 表示第 $ i $ 个学校的人数
发现 $ g1, g2 $ 是一个背包,可以压成一位来搞
记 $ f[j][k] $ 同之前的定义,滚掉第一维,用于转移有限制的城市和学校
对于城市,不同阵营的老师对派系的影响是不同的,因此记 $ h=f $ 记录不同派系的转移
先是对学校的转移( $ ban[i] $ 为 $ i $ 学校不喜欢的导师)
$ f[j][k]=\left\{ \begin{matrix} f[j][k-B[v],ban[i]!=0 \\f[j][k],ban[i]!=1 \end{matrix} \right\} $
$ g[j][k]=\left\{ \begin{matrix} g[j][k-B[v],ban[i]!=2 \\g[j][k],ban[i]!=3 \end{matrix} \right\} $
对于城市的转移
$ f[i][j]=f[i-A[l]][j]+g[i][j] $
考虑如何合并答案
枚举 $ f[i][j] $,则
$ sum-i-c1 \leq x \leq c0-i $,$ x $ 为 $ 1 $ 阵营的人数
$ sum-j-d1 \leq y \leq d0-j $,$ y $ 为 $ 1 $ 派系的人数
则没有限制的方案数为 $ \sum_{x=sum-i-c1}^{c0-i}\times \sum_{y=sum-j-d1}^{d0-i} $,前缀和优化即可 $ O(1) $ 询问
时间效率:$ O(km^2) $,时间主要在 $ f $ 上,但是跑不满
代码
代码写丑了,常数比较大
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define pb push_back 4 #define clr(s) memset(s,0,sizeof s) 5 #define _(d) while(d(isdigit(ch=getchar()))) 6 using namespace std; 7 int R(){ 8 int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48; 9 _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;} 10 const int N=3e3+5,P=998244353; 11 int n,m,K,g1[N],g2[N],f[N][N],h[N][N],c0,c1,d0,d1,ban[N],Ban[N],A[N],B[N],fa[N],sum,ans,s0,s1; 12 vector<int>p[N]; 13 void clean(){ 14 clr(g1),clr(g2),clr(f),clr(h),clr(A),clr(B),clr(fa); 15 for(int i=1;i<=m;i++)p[i].clear(); 16 sum=s0=s1=ans=0; 17 } 18 int make(int x,int y){ 19 int l0=max(0,sum-x-c1),r0=c0-x; 20 int l1=max(0,sum-y-d1),r1=d0-y; 21 if(l0>r0||l1>r1)return 0; 22 return 1ll*(g1[r0]-(l0?g1[l0-1]:0)+P)*(g2[r1]-(l1?g2[l1-1]:0)+P)%P; 23 } 24 int main(){ 25 for(int T=R();T--;clean()){ 26 memset(ban,-1,sizeof ban); 27 memset(Ban,-1,sizeof Ban); 28 n=R(),m=R(),c0=R(),c1=R(),d0=R(),d1=R(); 29 for(int i=1;i<=n;i++){ 30 fa[i]=R(),B[i]=R(); 31 sum+=B[i],A[fa[i]]+=B[i]; 32 p[fa[i]].pb(i); 33 } 34 K=R(); 35 for(int i=1;i<=K;i++){ 36 int id=R(),fl=R(); 37 ban[id]=Ban[fa[id]]=fl; 38 } 39 g1[0]=g2[0]=1; 40 for(int i=1;i<=m;i++) 41 if(!~Ban[i]&&A[i]) 42 for(int j=min(c0,sum);j>=A[i];j--) 43 g1[j]=(g1[j-A[i]]+g1[j])%P; 44 for(int i=1;i<=c0;i++)g1[i]=(g1[i]+g1[i-1])%P; 45 for(int i=1;i<=n;i++) 46 if(!~ban[i]) 47 for(int j=min(d0,sum);j>=B[i];j--) 48 g2[j]=(g2[j-B[i]]+g2[j])%P; 49 for(int i=1;i<=d0;i++)g2[i]=(g2[i]+g2[i-1])%P; 50 f[0][0]=1; 51 for(int i=1;i<=m;i++) 52 if(~Ban[i]&&A[i]){ 53 for(int x=min(c0,s0);~x;x--) 54 for(int y=min(d0,s1);~y;y--) 55 h[x][y]=f[x][y]; 56 for(int v:p[i])if(ban[v]!=-1){ 57 s1+=B[v]; 58 int f00=ban[v]^0?1:0,f01=ban[v]^1?1:0,f10=ban[v]^2?1:0,f11=ban[v]^3?1:0; 59 for(int x=min(c0,s0);~x;x--) 60 for(int y=min(d0,s1);~y;y--) 61 if(y>=B[v]){ 62 f[x][y]=(f[x][y]*f01+f[x][y-B[v]]*f00)%P; 63 h[x][y]=(h[x][y]*f11+h[x][y-B[v]]*f10)%P; 64 } 65 else f[x][y]=f[x][y]*f01,h[x][y]=h[x][y]*f11; 66 } 67 s0+=A[i]; 68 for(int x=min(c0,s0);~x;x--) 69 for(int y=min(c0,s1);~y;y--) 70 if(x>=A[i])f[x][y]=(f[x-A[i]][y]+h[x][y])%P; 71 else f[x][y]=h[x][y]; 72 } 73 for(int i=0;i<=min(s0,c0);i++) 74 for(int j=0;j<=min(s1,d0);j++) 75 ans=(ans+1ll*f[i][j]*make(i,j))%P; 76 cout<<ans<<endl; 77 } 78 return 0; 79 }