zoukankan      html  css  js  c++  java
  • 洛谷P5289 皮配

    解:观察一波部分分。

    首先小数据直接暴力4n,然后考虑背包。设f[i][a][b][c]表示前i个学校中前三位导师分别有多少人,第四位导师可以直接推出来。

    然后暴力枚举每一个人放在哪进行背包。

    进一步发现,因为限制条件全是跟行列有关的,所以我们设f[i][a][b]表示前i个学校,第一列和第一行分别有多少人。这样也能够控制满足那4个限制。

    于是我们有了一个m2n的50分DP。

    然后发现k = 0的时候行列独立。于是对行列分别DP,然后乘起来,这样有70分。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 2510, MO = 998244353;
      4 
      5 int C0, D0, C1, D1, n, c, belong[N], s[N], sum[N], K, d[N], lm[5];
      6 int f[2][2][N][N];
      7 std::vector<int> v[N];
      8 
      9 inline void clear() {
     10     for(int i = 1; i <= n; i++) {
     11         v[i].clear();
     12         sum[i] = 0;
     13         d[i] = 0;
     14     }
     15     memset(f, 0, sizeof(f));
     16     return;
     17 }
     18 
     19 inline void solve() {
     20     scanf("%d%d%d%d%d%d", &n, &c, &C0, &C1, &D0, &D1);
     21     lm[1] = std::min(C0, D0);
     22     lm[2] = std::min(C0, D1);
     23     lm[3] = std::min(C1, D0);
     24     lm[4] = std::min(C1, D1);
     25     for(int i = 1; i <= n; i++) {
     26         scanf("%d%d", &belong[i], &s[i]);
     27     }
     28     scanf("%d", &K);
     29     for(int i = 1, x; i <= K; i++) {
     30         scanf("%d", &x);
     31         scanf("%d", &d[x]);
     32         d[x]++;
     33     }
     34 
     35     for(int i = 1; i <= n; i++) {
     36         v[belong[i]].push_back(i);
     37         sum[belong[i]] += s[i];
     38     }
     39 
     40     if(n > 30) {
     41 
     42 #define h0 f[0][0][0]
     43 #define h1 f[1][1][1]
     44 
     45         h0[0] = h1[0] = 1;
     46         int tot = 0;
     47         for(int i = 1; i <= c; i++) {
     48             int limit = v[i].size();
     49             if(!limit) continue;
     50             int Sum = 0;
     51             for(int j = 0; j < limit; j++) {
     52                 int t = v[i][j]; /// city i school t
     53                 Sum += s[t];
     54                 for(int V = D0; V >= s[t]; V--) {
     55                     (h0[V] += h0[V - s[t]]) %= MO;
     56                 }
     57             }
     58             for(int V = C0; V >= Sum; V--) {
     59                 (h1[V] += h1[V - Sum]) %= MO;
     60             }
     61             tot += Sum;
     62         }
     63 
     64         int ans = 0;
     65         for(int V1 = std::max(0, tot - D1); V1 <= D0; V1++) {
     66             for(int V2 = std::max(0, tot - C1); V2 <= C0; V2++) {
     67                 (ans += 1ll * h0[V1] * h1[V2] % MO) %= MO;
     68             }
     69         }
     70         printf("%d
    ", ans);
     71 
     72 #undef h0
     73 #undef h1
     74 
     75         return;
     76     }
     77 
     78     int Sum = 0, FLAG = 0;
     79     f[0][1][0][0] = f[0][0][0][0] = 1;
     80     for(int i = 1; i <= c; i++) {
     81         int limit = v[i].size();
     82         if(!limit) continue;
     83         for(int j = 0; j < limit; j++) {
     84             int t = v[i][j]; /// city i school t
     85             Sum += s[t];
     86             FLAG ^= 1;
     87             int (*f0)[N] = f[FLAG][0], (*f1)[N] = f[FLAG][1], (*g0)[N] = f[FLAG ^ 1][0], (*g1)[N] = f[FLAG ^ 1][1];
     88             for(int V1 = 0; V1 <= D0 && V1 <= Sum; V1++) {
     89                 for(int V2 = 0; V2 <= C0 && V2 <= Sum; V2++) {
     90                     if(d[t] != 1 && V1 >= s[t] && V2 >= s[t])  /// 1
     91                         f0[V1][V2] = g0[V1 - s[t]][V2 - s[t]];
     92                     else
     93                         f0[V1][V2] = 0;
     94                     if(d[t] != 2 && V2 >= s[t] && Sum - V1 >= s[t]) /// 2
     95                         (f0[V1][V2] += g0[V1][V2 - s[t]]) %= MO;
     96                     if(d[t] != 3 && V1 >= s[t] && Sum - V2 >= s[t]) /// 3
     97                         f1[V1][V2] = g1[V1 - s[t]][V2];
     98                     else
     99                         f1[V1][V2] = 0;
    100                     if(d[t] != 4 && Sum - V1 >= s[t] && Sum - V2 >= s[t]) /// 4
    101                         (f1[V1][V2] += g1[V1][V2]) %= MO;
    102                 }
    103             }
    104         }
    105         ///
    106         for(int V1 = 0; V1 <= Sum; V1++) {
    107             for(int V2 = 0; V2 <= Sum; V2++) {
    108                 (f[FLAG][0][V1][V2] += f[FLAG][1][V1][V2]) %= MO;
    109                 f[FLAG][1][V1][V2] = f[FLAG][0][V1][V2];
    110             }
    111         }
    112     }
    113 
    114     int ans = 0;
    115     for(int V1 = std::max(0, Sum - D1); V1 <= D0; V1++) {
    116         for(int V2 = std::max(0, Sum - C1); V2 <= C0; V2++) {
    117             (ans += f[FLAG][0][V1][V2]) %= MO;
    118         }
    119     }
    120     printf("%d
    ", ans);
    121     return;
    122 }
    123 
    124 int main() {
    125 
    126     freopen("in.in", "r", stdin);
    127     freopen("right.out", "w", stdout);
    128 
    129     int T;
    130     scanf("%d", &T);
    131     while(T--) {
    132         solve();
    133         clear();
    134     }
    135     return 0;
    136 }
    70分代码

    正解:

    把上面两种部分分结合起来。发现无标号的行列,有标号这三个东西全都互相独立。

    具体来说,把城市和学校都分成两类,有标记和没标记。如果一个学校有标记那么它城市也有标记。然后枚举每个无标记城市,对上下做DP。然后枚举每个无标记学校,对左右做DP。

    然后对有标记的进行50分DP。这里有一个坑点......当你一个城市总人数大于C0但是受限制人数小于C0的时候,你可能会多算一种方案,即受限制的学校在上面,但是别的却在下面。

    出现这个问题的原因是∑school != city,因为有些无标记学校已经拿出去算了。

    所以我们要想办法把一个城市的有无标记的学校都限制在同一横条。具体来说......之前DP的时候,我们是每加一个学校就同时处理行列限制,而现在是先分成上下两部分,然后分别转移每个学校的左右。最后转移这个城市的上下,相当于为那些无标记的学校预留了位置。

    记得把上下界开松一点......还有就是对城市DP的时候跳过空城市。

    最后统计答案的时候,对于有标记的每一个状态,考虑把无标记的怎么塞进去。有个上下界的限制,在这个上下界之中的每个方法都是合法的,于是我们对于无标记的DP数组做前缀和,然后相乘就行了...

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 5010, MO = 998244353;
      4 
      5 int C0, D0, C1, D1, n, c, belong[N], s[N], K, d[N], h0[N], h1[N], sum[N];
      6 int f[2][2][N][N], tot;
      7 bool vis[N];
      8 std::vector<int> v[N];
      9 
     10 inline void clear() {
     11     for(int i = 1; i <= n || i <= c; i++) {
     12         v[i].clear();
     13         sum[i] = d[i] = vis[i] = 0;
     14     }
     15     tot = 0;
     16     memset(f, 0, sizeof(f));
     17     memset(h0, 0, sizeof(h0));
     18     memset(h1, 0, sizeof(h1));
     19     return;
     20 }
     21 
     22 inline int cal(int V1, int V2) {
     23     int l1 = std::max(0, tot - D1 - V1), r1 = D0 - V1;
     24     int l2 = std::max(0, tot - C1 - V2), r2 = C0 - V2;
     25     if(l1 > r1 || l2 > r2) return 0;
     26     int temp1 = (h0[r1] - (l1 ? h0[l1 - 1] : 0) + MO) % MO, temp2 = (h1[r2] - (l2 ? h1[l2 - 1] : 0) + MO) % MO;
     27     return 1ll * temp1 * temp2 % MO;
     28 }
     29 
     30 inline void solve() {
     31     scanf("%d%d%d%d%d%d", &n, &c, &C0, &C1, &D0, &D1);
     32     for(int i = 1; i <= n; i++) {
     33         scanf("%d%d", &belong[i], &s[i]);
     34         v[belong[i]].push_back(i);
     35         sum[belong[i]] += s[i];
     36         tot += s[i];
     37     }
     38     scanf("%d", &K);
     39     for(int i = 1, x; i <= K; i++) {
     40         scanf("%d", &x);
     41         scanf("%d", &d[x]);
     42         d[x]++;
     43         vis[belong[x]] = 1;
     44     }
     45     
     46     int LM = std::max(tot, std::max(C0 + C1, D0 + D1));
     47     /// first no limit DP
     48     h0[0] = h1[0] = 1;
     49     int Sum = 0;
     50     for(int i = 1; i <= n; i++) {
     51         if(d[i]) continue;
     52         Sum += s[i];
     53         for(int V = Sum; V >= s[i]; V--) {
     54             (h0[V] += h0[V - s[i]]) %= MO;
     55         }
     56     }
     57     for(int i = 1; i <= LM; i++) {
     58         (h0[i] += h0[i - 1]) %= MO;
     59     }
     60     
     61     Sum = 0;
     62     for(int i = 1; i <= c; i++) {
     63         if(vis[i] || !sum[i]) continue;
     64         Sum += sum[i];
     65         for(int V = Sum; V >= sum[i]; V--) {
     66             (h1[V] += h1[V - sum[i]]) %= MO;
     67         }
     68     }
     69     for(int i = 1; i <= LM; i++) {
     70         (h1[i] += h1[i - 1]) %= MO;
     71     }
     72 
     73     /// second limit DP
     74     Sum = 0;
     75     int FLAG = 0, Sum2 = 0;
     76     f[0][1][0][0] = f[0][0][0][0] = 1;
     77     for(int i = 1; i <= c; i++) {
     78         int limit = v[i].size();
     79         if(!limit || !vis[i]) continue;
     80         Sum2 += sum[i];
     81         for(int j = 0; j < limit; j++) {
     82             int t = v[i][j]; /// city i school t
     83             if(!d[t]) continue;
     84             Sum += s[t];
     85             FLAG ^= 1;
     86             int (*f0)[N] = f[FLAG][0], (*f1)[N] = f[FLAG][1], (*g0)[N] = f[FLAG ^ 1][0], (*g1)[N] = f[FLAG ^ 1][1];
     87             for(int V1 = 0; V1 <= D0 && V1 <= Sum; V1++) {
     88                 for(int V2 = 0; V2 <= C0 && V2 <= Sum2; V2++) {
     89                     if(d[t] != 1 && V1 >= s[t])  /// 1
     90                         f0[V1][V2] = g0[V1 - s[t]][V2];
     91                     else
     92                         f0[V1][V2] = 0;
     93                     if(d[t] != 2 && Sum - V1 >= s[t]) /// 2
     94                         (f0[V1][V2] += g0[V1][V2]) %= MO;
     95 
     96                     if(d[t] != 3 && V1 >= s[t]) /// 3
     97                         f1[V1][V2] = g1[V1 - s[t]][V2];
     98                     else
     99                         f1[V1][V2] = 0;
    100                     if(d[t] != 4 && Sum - V1 >= s[t]) /// 4
    101                         (f1[V1][V2] += g1[V1][V2]) %= MO;
    102                 }
    103             }
    104         }
    105         ///
    106 
    107         FLAG ^= 1;
    108         for(int V1 = 0; V1 <= Sum && V1 <= D0; V1++) {
    109             for(int V2 = 0; V2 <= Sum2 && V2 <= C0; V2++) {
    110                 /// up
    111                 if(V2 >= sum[i])
    112                     f[FLAG][0][V1][V2] = f[FLAG ^ 1][0][V1][V2 - sum[i]];
    113                 else
    114                     f[FLAG][0][V1][V2] = 0;
    115                 /// down
    116                 if(Sum2 - V2 >= sum[i])
    117                     (f[FLAG][0][V1][V2] += f[FLAG ^ 1][1][V1][V2]) %= MO;
    118                 f[FLAG][1][V1][V2] = f[FLAG][0][V1][V2];
    119             }
    120         }
    121     }
    122 
    123     int ans = 0;
    124     for(int V1 = 0; V1 <= D0; V1++) {
    125         for(int V2 = 0; V2 <= C0; V2++) {
    126             (ans += 1ll * f[FLAG][0][V1][V2] * cal(V1, V2) % MO) %= MO;
    127         }
    128     }
    129     printf("%d
    ", ans);
    130     return;
    131 }
    132 
    133 int main() {
    134 
    135     int T;
    136     scanf("%d", &T);
    137     while(T--) {
    138         solve();
    139         if(T) {
    140             clear();
    141         }
    142     }
    143     return 0;
    144 }
    AC代码

    这TM考场上谁能写出来啊....十个我也搞不倒......

  • 相关阅读:
    pip国内源
    高级信息系统项目管理师十大管理优秀范文
    DOM是什么
    js中!!的妙用
    Angular中@Output()的使用方法
    Js数组内对象去重
    JS去除对象或数组中的空值('',null,undefined,[],{})
    JS数组与字符串相互转换
    Js删除数组中的空值
    promise.all的应用场景举例
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10726002.html
Copyright © 2011-2022 走看看