「十二省联考 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 }
View Code

 

posted @ 2019-04-09 16:34  Chm_wt  阅读(400)  评论(0编辑  收藏  举报