Educational Codeforces Round 137 (Rated for Div. 2) (A-E)题解

比赛链接

A. Password

大水题,求个组合数就水掉了。

点击查看代码
#include <bits/stdc++.h> using namespace std; #define N 1000010 #define ll long long template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } vector <int> a; int fac[N]; void prepare(){ fac[0] = fac[1] = 1; for(int i = 1; i <= 10; i++) fac[i] = fac[i-1] * i; return ; } int C(int a, int b){ return fac[b] / (fac[a] * fac[b-a]); } int main(){ // freopen("hh.txt", "r", stdin); int T; read(T); prepare(); while(T--){ // a.clear(); int n; read(n); for(int i = 1; i <= n; i++){ int x; read(x); } cout << C(2, 10 - n) * 6 << endl; } return 0; }

B. Permutation Value

大水题。首先可以知道小的数字在一个排列中是不可缺少的。所以把小数字尽量放远一点即可。

点击查看代码
#include <bits/stdc++.h> using namespace std; #define N 1000010 #define ll long long template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } int ans[N]; int main(){ // freopen("hh.txt", "r", stdin); int T;read(T); while(T--){ memset(ans, 0, sizeof(ans)); int n; read(n); int tot = 0; int p = 1; int dis = 0; for(int i = 1; i <= n; i++){ ans[p] = i; if(i % 2 == 0) p = dis + 1; else p = n - dis, dis++; } for(int i = 1; i <= n; i++){ printf("%d ", ans[i]); } cout << endl; } return 0; }

C. Save the Magazines

相对没那么水。设 dp 数组 dpi,0/1 表示第 i 件物品为止,是否转移到前一个物品,情况下的最大值。公式见代码。注意讨论是否可以转移到前一个物品以及前提条件。

点击查看代码
#include <bits/stdc++.h> using namespace std; #define N 1000010 #define ll long long template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } int n; char s[N]; int a[N]; int dp[N][2]; int main(){ // freopen("hh.txt", "r", stdin); int T; read(T); while(T--){ // memset(dp, 0, sizeof(dp)); read(n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) read(a[i]); for(int i = 1; i <= n; i++){ if(s[i] == '1'){ if(s[i-1] == '1') dp[i][1] = dp[i-1][1] + a[i-1]; else dp[i][1] = dp[i-1][0] + a[i-1]; dp[i][0] = max(dp[i-1][0], dp[i-1][1]) + a[i]; } else{ dp[i][1] = -1e9; dp[i][0] = max(dp[i-1][0], dp[i-1][1]); } } cout << max(dp[n][0], dp[n][1]) << endl; } return 0; }

D. Problem with Random Tests

本次比赛争议很大的一道题。由于全是随机数据,难度大大降低。首先容易想到,

可以贪心找到以 1 开头的一个长串,这样肯定可以保证结果尽量大。然后考虑寻找第二个串来跟他 or 一下。由于纯随机数据,复杂度期望 O(logN),很难卡掉,直接一个个暴力比较即可。

(这道题使用 string 会比较好写。本人比赛时太傻了,使用了数组。。。。)

点击查看代码
#include <bits/stdc++.h> using namespace std; #define N 1000010 #define ll long long template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } int n; char t[N]; int s[N]; int tmp[N]; int ans[N]; int m; bool check(int *a, int *b, int n){ // 检查 a 是否大于等于 b for(int i = 1; i <= n; i++){ if(a[i] < b[i]) return 0; if(a[i] > b[i]) return 1; if(a[i] == b[i]) continue; } return 1; } int main(){ // freopen("hh.txt", "r", stdin); read(m); scanf("%s", t + 1); int p = -1; for(int i = 1; i <= m; i++) if(t[i] == '1'){ p = i; break; } if(p == -1){ cout << 0 << endl; return 0; } n = m - p + 1; // 当前串的总长度 int id = 0; for(int i = p; i <= m; i++){ s[++id] = t[i] - '0'; // 第一个串 } for(int i = 1; i <= n; i++){ if(s[i] == 0){ p = i; break; } } memcpy(ans, s, sizeof(ans)); int len = n - p + 1; // 小串的长度 for(int i = 1; i + len <= n; i++){ // i: 小船的头 memcpy(tmp, s, sizeof(tmp)); // 存一个副本 if(s[i] != 1) continue; for(int j = p, now = 0; j <= n && now < len; j++, now++){ tmp[j] |= s[i+now]; } if(check(tmp, ans, n)) memcpy(ans, tmp, sizeof(ans)); } for(int i = 1; i <= n; i++) printf("%d", ans[i]); //未完待续 return 0; }

E. FTL

本蒟蒻到 E 题便有些吃力了。考虑 dp。设 dpx 表示造成 x 伤害所需要的最小时间。 考虑到若将剩余血量设为状态,可能出现负数,造成下标问题,故将其反向。

状态转移: 对于当前血量 x,我们有三种情况:用一号大炮单独打一次,用二号大炮单独打一次,二者一起打一次(中间可能包扩各自打)。对于前两种情况,比较简单:

dp[x]=min(dp[x(p1p)]+t1,dp[x(p2p)]+t2

对于第三种情况,画图考虑:

对于 t2 大于 t1 的情况,如此考虑:两门炮先各自打若干炮,然后最后一起打一炮。这样就可以覆盖所有的情况了。

点击查看代码
#include <bits/stdc++.h> using namespace std; #define N 1000010 #define ll long long template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } ll dp[N]; ll p1, t1; ll p2, t2; ll M, p; int main(){ // freopen("hh.txt", "r", stdin); // freopen("out.txt", "w", stdout); read(p1), read(t1); read(p2), read(t2); read(M), read(p); memset(dp, 0x3f3f3f3f3f3f3f, sizeof(dp)); dp[0] = 0; for(int i = 1; i <= M; i++){ dp[i] = min(dp[i], dp[max(0ll, i - p1 + p)] + t1); dp[i] = min(dp[i], dp[max(0ll, i - p2 + p)] + t2); for(int j = 1; j <= i; j++){ if(j * t1 >= t2){ ll tmp = (j - 1) * (p1 - p) + ((j * t1 - t2) / t2) * (p2 - p) + (p1 + p2 - p); dp[i] = min(dp[i], dp[max(0ll, (ll)i-tmp)] + j * t1); } if(j * t2 >= t1){ ll tmp = (j - 1) * (p2 - p) + ((j * t2 - t1) / t1) * (p1 - p) + (p1 + p2 - p); dp[i] = min(dp[i], dp[max(0ll, (ll)i-tmp)] + j * t2); } } } cout << dp[M] << endl; return 0; }

F和G:不会

文章来源: https://www.cnblogs.com/wondering-world/p/16803622.html
All rights reserved ©雪之下,树之旁

__EOF__

本文作者雪之下,树之旁
本文链接https://www.cnblogs.com/wondering-world/p/16803622.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   雪之下,树之旁  阅读(170)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示