====== CF Edu Round 93 ====== ===== A ===== ==== 题意: ==== 给你一个序列,问这些序列中取三个数字无法构成三角形的元素,随意一组,如果都可以组成,那么输出−1。 ==== 思路: ==== 三角形两条边的和必大于第三条边,那么我们直接将两个最小的加起来直接和最大进行相比,如果这个可以构成三角形的话,那么这个里面都可以构成三角形。 #include #include #include #include #include #include #include using namespace std; int pic[100050]; int main() { int t = 0; cin >> t; while (t--) { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> pic[i]; if (pic[1] + pic[2] <= pic[n]) printf("1 2 %d\n", n); else puts("-1"); } return 0; } ===== B ===== ==== 题意: ==== 有两个人,每一次都可以取序列中连续的部分,然后取完的两边会相邻,问先取的那个人最多可以取多少个1,两个人都取最优。 ==== 思路: ==== 直接将连续的1个数全部提取出来,先取的是拿最大的,后取的第二大直到取完。 #include #include #include #include #include #include #include using namespace std; char s[1024]; int num[1024], tot; int main() { int t; cin >> t; while(t--) { cin >> s; tot = 0; int tem = 0; for (int i = 0; s[i];i++) { if (s[i] == '1') tem++; else { if (tem != 0) { num[tot++] = tem; tem = 0; } } } if(tem != 0) num[tot++] = tem; sort(num, num + tot); int ans = 0; for (int i = tot - 1; i >= 0;i-=2) ans += num[i]; cout << ans << endl; } return 0; } ===== C ===== ==== 题意: ==== 在一个序列中,我们需要求出有多少个区间满足$\sum^r_{i = l}a_i=r−l+1$。 #include #include #include #include #include #include #include using namespace std; typedef long long LL; const int MAX = 1e5 + 20; int a[MAX]; int sum[MAX]; int cnt[2000090]; char s[MAX]; LL ans = 0; int main() { int t; cin >> t; while (t--) { int n; ans = 0; cin >> n; cin >> s; for (int i = 0; i < n; i++) { a[i] = s[i] - '0'; sum[i] = a[i]; } for (int j = 1; j < n; j++) sum[j] += sum[j - 1]; for (int i = 0; i < n; i++) sum[i] -= i + 1; for (int i = 0; i <= n * 10 * 2 + 2; i++) cnt[i] = 0; cnt[0 + n * 10] = 1; for (int i = 0; i < n; i++) { if (cnt[sum[i] + n * 10]) ans += cnt[sum[i] + n * 10]; cnt[sum[i] + n * 10]++; } cout << ans << endl; } } ===== D ===== ==== 题意: ==== 给你三个序列,你每次可以选择三个序列中的两个元素,但不能是相同序列的,然后进行相乘,问最后的相乘的和最大是多少。 ==== 题解: ==== ​ 先从大到小排序,然后暴力三维dp即可$dp[i][j][k]$表示r,g,b分别选到第i,j,k个时的最大值。 #include #include #include #include #include #include #include using namespace std; typedef long long ll; int R[256], G[256], B[256]; int r, g, b; ll dp[256][256][256]; ll ans; void mfs(int x,int y,int z) { if ((x > r and y >g) or( z >b and y >g) or (x>r and z>b)) { dp[x][y][z] = 0; return; } if (dp[x][y][z] != 0) return; if (x<=r and y<=g) { mfs(x + 1, y + 1, z); dp[x][y][z] = max(dp[x][y][z], dp[x + 1][y + 1][z] + R[x] * G[y]); } if (x<=r and z<=b) { mfs(x + 1, y, z+1); dp[x][y][z] = max(dp[x][y][z], dp[x + 1][y][z + 1] + R[x] * B[z]); } if (y<=g and z<=b) { mfs(x, y + 1, z+1); dp[x][y][z] = max(dp[x][y][z], dp[x][y + 1][z + 1] + B[z] * G[y]); } //dp[x][y][z] = max(dp[x + 1][y + 1][z] + R[x] * G[y], max(dp[x + 1][y][z + 1] + R[x] * B[z], dp[x][y + 1][z + 1] + B[z] * G[y])); ans = max(ans, dp[x][y][z]); } bool cam(int x,int y) { return x > y; } int main() { scanf("%d%d%d", &r, &g, &b); //memset(dp, -1, sizeof(dp)); for (int i = 1; i <= r;i++) { int tem; scanf("%d", &tem); R[i] = tem; } for (int i = 1; i <= g;i++) { int tem; scanf("%d", &tem); G[i] = tem; } for (int i = 1; i <= b;i++) { int tem; scanf("%d", &tem); B[i] = tem; } sort(R + 1, R + r + 1, cam); sort(G + 1, G + g + 1, cam); sort(B + 1, B + b + 1, cam); mfs(1, 1, 1); cout << ans << endl; return 0; } ===== E ===== ==== 题意: ==== 我们总共有两种法术,闪电法术、火焰法术,闪电法术之后能够将下一个法术的伤害翻倍,现在有两种操作学习一种法术/忘记一种法术,问你每每次操作后最大的伤害是多少。 ==== 题解: ==== 贪心,set乱搞。