[十二省联考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;
}
原文地址:https://www.cnblogs.com/newbielyx/p/13150337.html