• [十二省联考2019]皮配


    Description

    题面

    简化版题面:

    (c) 个豆荚,共 (n) 颗豆子,每颗豆子都有自己的重量,现在需要将给豆子设定为(黄色/绿色,圆粒/皱粒),要求满足以下条件:

    1. 给定这四种性状的阀值 (C0,C1,D0,D1),要求为这种性状的豆子重量和不能超过该阀值。

    2. 与此同时,这 (n) 颗豆子中存在 (k) 颗顽皮豆,顽皮豆都有自己的想法,比如拒绝成为(黄圆/黄皱/绿圆/绿皱)。

    3. 同一个豆荚里的豆子必须同时为黄色同时为绿色

    求有多少种给豆子设定的方案,答案对 (998244353) 取模。

    Solution

    本题只考查了联赛级别的知识点背包,很普及组吧。好评!XD

    算法一 暴力

    纯暴力。

    (f_{i,0/1,x,y,z}) 为第 (i) 个学校选择的是红/蓝阵营,前三位导师分别有 (x,y,z) 个选手的方案数,然后枚举每个学校进行转移即可。复杂度 (O(nM^3)),预计得分 (30pts+)

    代码

    其实并不需要设三维的 ( ext{dp}),只需设状态 (f_{i,0/1,x,y}) 表示第 (i) 个学校选择的是红/蓝阵营,选择蓝阵营的有 (x) 人,鸭派系的有 (y) 人,因为一个选手必定属于其中一个阵营/派系,复杂度 (O(nM^2)),预计得分 (50pts)

    代码

    算法二 (k=0)

    考虑 (k=0) 的情况。

    此时任何学校都没有导师的限制,可以发现先确定阵营再确定派系,与同时确定阵营与派系(即直接确定某位导师)所得到的方案数是等价的。(类似于生物里的两对相对性状?)

    (f_{i,1/0,j}) 为第 (i) 个学校选择红/蓝阵营,且前 (i) 个学校选择蓝阵营的有 (j) 个人的方案数,(g_{i,j}) 为前 (i) 个学校选择鸭派系的有 (j) 个人的方案数,那么分别计算出来后,进行合并,即总方案数为

    [sum limits_{i=S-C_1}^{C_0} sum limits_{i=D_1}^{D_0} (f_{n,0,i} + f_{n,1,i}) imes g_{n,j} ]

    其实本质上就是背包及背包合并

    复杂度 (O(nM)),结合前面的算法可以拿到 (70pts)

    代码

    随便写写暴力就70pts了

    算法三 正解

    继续沿着算法二的思路进行思考,拓展到更为一般的情况。

    还是设 (f)(g) 分别表示阵营和派系的方案数,考虑如何处理学校对导师的限制。

    下面对于阵营的划分,都基于城市为单位进行考虑;对于派系的划分,都基于学校为单位进行考虑(若以城市为单位进行 ( ext{dp}),一个没有限制的学校因为同城市其它学校的偏好被 ( ext{dp}) 到会感觉很不爽 ( ext{2333}))。

    一个城市有限制,当且仅当城市内的学校有限制。

    所以对于那些没有限制的城市和学校,我们还是可以仿照算法二,直接 ( ext{dp})(f)(g)

    而对于那些有限制的学校/城市,由于 (k) 很小,只有 (30),我们可以仿照 (50pts) 的算法,暴力 ( ext{dp}) 出方案数,记为 (F)

    (F_{i,0/1,j,k}) 表示前 (i) 个有限制的学校,第 (i) 个学校加入了红/蓝阵营,加入红阵营的有 (j) 人,这些学校所属城市加入了鸭派系的有 (k) 人的方案数。

    最后,进行合并,只要枚举有限制的学校的派系、阵营人数,然后用 (f) 去匹配无限制城市的阵营人数的上下界,用 (g) 去匹配无限制的学校的派系人数的上下界,再全部乘起来就好了。

    简单的背包,吐了XDXDXD

    代码

    Code

    Talk is cheap. Show me the code.

    Tips:

    1. 滚动数组每轮记得清零!
    2. 不要用 memset,贼慢!
    #include <bits/stdc++.h>
    using namespace std;
    
    int ty() {
      int x = 0, f = 1; char ch = getchar();
      while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
      while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
      return x * f;
    }
    
    typedef long long ll;
    const int _ = 2500 + 10;
    const int mod = 998244353;
    int N, C, K, C0, C1, D0, D1, sum;
    int f[5005], g[5005], F[2][2][5005][5005];
    struct school {
      int city, num, prf;
      bool operator<(const school &x) const {
        if ((prf != 0) ^ (x.prf != 0)) return (prf != 0) > (x.prf != 0);
        return city < x.city;
      }
    } scl[_];
    struct city { int num, hate; } ct[_];
    
    void Inc(int &x, const int &y) { x = x + y < mod ? x + y : x + y - mod; }
    
    void clear() {
      sum = 0;
      // memset(f, 0, sizeof(f));
      // memset(g, 0, sizeof(g));
      // memset(F, 0, sizeof(F));
      memset(ct, 0, sizeof(ct));
      memset(scl, 0, sizeof(scl));
    }
    
    void init() {
      N = ty(), C = ty();
      C0 = ty(), C1 = ty(), D0 = ty(), D1 = ty();
      for (int i = 1; i <= N; ++i) {
        scl[i].city = ty(), scl[i].num = ty();
        sum += scl[i].num;
      }
      K = ty();
      for (int i = 1; i <= K; ++i) {
        int x = ty();
        scl[x].prf = ty() + 1;
      }
      sort(scl + 1, scl + N + 1);
      for (int i = 1; i <= N; ++i) {
        ct[scl[i].city].num += scl[i].num;
        if (scl[i].prf) ct[scl[i].city].hate = true;
      }
    }
    
    ll calc1(int l, int r) {
      return l > r ? 0 : (l <= 0 ? g[r] : (g[r] - g[l - 1] + mod) % mod);
    }
    ll calc2(int l, int r) {
      return l > r ? 0 : (l <= 0 ? f[r] : (f[r] - f[l - 1] + mod) % mod);
    }
    
    void dp() {
      f[0] = 1;
      for (int i = 1; i <= C; ++i)
        if (!ct[i].hate && ct[i].num)
          for (int j = C0; j >= ct[i].num; --j) Inc(f[j], f[j - ct[i].num]);
      for (int i = 1; i <= C0; ++i) f[i] = (f[i] + f[i - 1]) % mod;
    
      g[0] = 1;
      for (int i = 1; i <= N; ++i)
        if (!scl[i].prf)
          for (int j = D0; j >= scl[i].num; --j) Inc(g[j], g[j - scl[i].num]);
      for (int i = 1; i <= D0; ++i) g[i] = (g[i] + g[i - 1]) % mod;
    
      F[0][0][0][0] = 1;
      int sum1 = 0, nw = 0;
      for (int i = 1; i <= K; ++i) {
        sum1 += scl[i].num;
        for (int x = 0; x <= C0; ++x) {
          for (int y = 0; y <= sum1; ++y) {
            if (scl[i].prf != 1) {
              if (scl[i].city != scl[i - 1].city) {
                if (x >= ct[scl[i].city].num && y >= scl[i].num) {
                  Inc(F[nw ^ 1][0][x][y],
                      F[nw][1][x - ct[scl[i].city].num][y - scl[i].num]);
                  Inc(F[nw ^ 1][0][x][y],
                      F[nw][0][x - ct[scl[i].city].num][y - scl[i].num]);
                }
              } else {
                if (y >= scl[i].num)
                  Inc(F[nw ^ 1][0][x][y], F[nw][0][x][y - scl[i].num]);
              }
            }
            if (scl[i].prf != 2) {
              if (scl[i].city != scl[i - 1].city) {
                if (x >= ct[scl[i].city].num) {
                  Inc(F[nw ^ 1][0][x][y], F[nw][1][x - ct[scl[i].city].num][y]);
                  Inc(F[nw ^ 1][0][x][y], F[nw][0][x - ct[scl[i].city].num][y]);
                }
              } else {
                Inc(F[nw ^ 1][0][x][y], F[nw][0][x][y]);
              }
            }
            if (scl[i].prf != 3) {
              if (scl[i].city != scl[i - 1].city) {
                if (y >= scl[i].num) {
                  Inc(F[nw ^ 1][1][x][y], F[nw][0][x][y - scl[i].num]);
                  Inc(F[nw ^ 1][1][x][y], F[nw][1][x][y - scl[i].num]);
                }
              } else {
                if (y >= scl[i].num)
                  Inc(F[nw ^ 1][1][x][y], F[nw][1][x][y - scl[i].num]);
              }
            }
            if (scl[i].prf != 4) {
              if (scl[i].city != scl[i - 1].city) {
                Inc(F[nw ^ 1][1][x][y], F[nw][0][x][y]);
                Inc(F[nw ^ 1][1][x][y], F[nw][1][x][y]);
              } else {
                Inc(F[nw ^ 1][1][x][y], F[nw][1][x][y]);
              }
            }
          }
        }
        for (int x = 0; x <= C0; ++x)
          for (int y = 0; y <= sum1; ++y) F[nw][0][x][y] = F[nw][1][x][y] = 0;
        nw ^= 1;
      }
    
      int ans = 0;
      for (int i = 0; i <= C0; ++i) {
        for (int j = 0; j <= sum1; ++j) {
          ll A = (F[nw][0][i][j] + F[nw][1][i][j]) % mod;
          ans = (1ll * ans + A * calc1(sum - D1 - j, D0 - j) % mod * calc2(sum - C1 - i, C0 - i) % mod) % mod;
        }
      }
      printf("%d
    ", ans);
      for (int i = 0; i <= C0; ++i) {
        f[i] = 0;
        for (int j = 0; j <= sum1; ++j)
          F[0][0][i][j] = F[0][1][i][j] = F[1][0][i][j] = F[1][1][i][j] = 0;
      }
      for (int i = 0; i <= D0; ++i) g[i] = 0;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("match.in", "r", stdin);
      freopen("match.out", "w", stdout);
    #endif
      int T = ty();
      while (T--) {
        clear();
        init();
        dp();
      }
      return 0;
    }
    
  • 相关阅读:
    Android开发工程师文集-1 小时学会SQLite
    Android开发工程师文集-1 小时学会各种Drawable
    Android开发工程师文集-1 小时学会各种Drawable
    Android精通教程-Android入门简介
    Android精通教程-Android入门简介
    AndroidStudio制作登录和注册功能的实现,界面的布局介绍
    AndroidStudio制作登录和注册功能的实现,界面的布局介绍
    Android开发的插件Code Generator与LayoutCreator的安装与使用,提升你的开发效率
    Android开发的插件Code Generator与LayoutCreator的安装与使用,提升你的开发效率
    AndroidStudio项目制作倒计时模块
  • 原文地址:https://www.cnblogs.com/newbielyx/p/13150337.html
Copyright © 2020-2023  润新知