zoukankan      html  css  js  c++  java
  • 「十二省联考 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 ight}}$。
    - 接下来 $1$ 行一个非负整数 $k$,表示选手有偏好的学校数目。
    - 接下来 $k$ 行,每行 $2$ 个整数 $i,p$,描述编号为 $i$ 的学校选手有偏好:
    - 其中,$p$ 为一个 $0$ 至 $3$ 之间的整数,描述该校选手不喜欢的导师:0 代表 Yazid,1 代表小 R,2 代表 Zayid,3 代表大 R。
    - 保证 $1leq ileq 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 ight}}$。

    对于所有测试点,保证 $Tleq 5$。

    对于所有测试点中的每一组数据,保证 $cleq nleq 1000$,$kleq 30$,$Mleq 2500$,$1leq 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{ egin{matrix} f[j][k-B[v],ban[i]!=0 \f[j][k],ban[i]!=1 end{matrix} ight} $

    $ g[j][k]=left{ egin{matrix} g[j][k-B[v],ban[i]!=2 \g[j][k],ban[i]!=3 end{matrix} ight} $

    对于城市的转移

    $ 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} imes 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
  • 相关阅读:
    [Effective C++ --009]确定对象被使用前已先被初始化
    [Effective C++ --008]别让异常逃离析构函数
    [Effective C++ --007]为多态基类声明virtual析构函数
    [Effective C++ --006]若不能使用编译器自动生成的函数,就该明确拒绝
    [Effective C++ --005]了解C++默默编写并调用哪些函数
    [000]socket通信--server和client实现的简单例子
    [014]模板-模板实参推导
    [013]模板-非类型模板参数
    [012]泛型--lambda表达式捕获
    U3d keyCode值对应的按键
  • 原文地址:https://www.cnblogs.com/chmwt/p/10677849.html
Copyright © 2011-2022 走看看