标签:洛谷 皮配 V1 int Sum P5289 V2 && MO
解:观察一波部分分。
首先小数据直接暴力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\n", 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\n", 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分代码
正解:
标签:洛谷,皮配,V1,int,Sum,P5289,V2,&&,MO 来源: https://www.cnblogs.com/huyufeifei/p/10726002.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。