Codeforces Round #652 (Div. 2) (补题ing)
cf补题 652
B - AccurateLee
题意:如果一个字符串有连续10,可以去掉1或者去掉0,问最短的字典序最小的串。
思路:前面的0和后面的1一定去不掉。中间的10无论怎么排列,都可以消成一个0,所以前后找一遍即可。
注意特判00001111这种一个都消不掉的。
void solve(){ cin >> n >> s + 1; int idx1 = 1, idx2 = 0; for(idx1 = 1; idx1 <= n; ++ idx1) if(s[idx1] == '1') break; for(idx2 = n; idx2 >= idx1; -- idx2) if(s[idx2] == '0') break; //printf("1 = %d 2 = %d\n", idx1, idx2); if(idx1 < idx2){ for(int i = 1; i < idx1; ++ i) printf("%c", s[i]); printf("0"); for(int i = idx2 + 1; i <= n; ++ i) printf("%c", s[i]); }else{ for(int i = 1; i < idx1; ++ i) printf("%c", s[i]); for(int i = idx2 + 1; i <= n; ++ i) printf("%c", s[i]); } cout << endl; }
C - RationalLee
题意:n个礼物送给m个人,每个人给mi个(mi的和等于n),每个礼物有一个价值。每个人的开心值为礼物中的价值最大+价值最小,问最大的总开心值。
思路:如果有人只得到一个礼物,那肯定给价值最大的,这样maxx == minn == 最大价值。
剩下的人,让要得到礼物最多的人先选,选当前最大,然后剩下的从小往大选,这样一定可以剩下更多价值大的供后面人选择。【除了maxx minn, 剩下礼物没有用,所以肯定尽快处理小的】。
void solve(){ ll ans = 0, idx; cin >> n >> k; for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]); for(int i = 1; i <= k; ++ i) scanf("%d", &b[i]); sort(a + 1, a + 1 + n, greater<int>() ); sort(b + 1, b + 1 + k); for(int i = 1; i <= k; ++ i) ans += a[i]; for(int i = 1, idx = n; i <= k; ++ i){ if(b[i] == 1) ans += a[i]; else{ for(; idx > k; -- idx){ ans += a[idx]; idx -= (b[i] - 1); } } } cout << ans << endl; }
D. TediousLee 【找规律,好玩好玩hao】
画图找规律emmmm.
称一个没有孩子的点为A, 只有一个孩子的点为B, 有三个孩子的点为C。
那么这一轮的A会变成下一轮的B(同时生成一个A),这一轮的B会变成下一轮的C,而这一轮的B又会给下一轮多生成两个A。
所以dp[i, A] = dp[i - 1, A] + dp[i - 1][B] * 2
dp[i, B] = dp[i - 1, A]
可以发现:至少有dp[i - 1, B]这么多的爪形结构新生成, 但是还会有之前早就生成的爪形结构,观察发现(我也不知道为什么,就是看出来的emm) 还要加上i - 3轮之前的答案。
用rec数组记录A, B的递推情况, dp数组记录答案。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 2000010, mod = 1e9 + 7; int n,k; ll dp[N] = {0,0,0,1,1,3,5,12}; ll rec[N][2]; void solve(){ rec[1][0] = rec[1][1] = 0; rec[2][0] = rec[2][1] = 1; for(int i = 3; i <= 2000000; ++ i){ rec[i][0] = rec[i - 1][1]; rec[i][1] = (rec[i - 1][1] + rec[i - 1][0] * 2) % mod; dp[i] = (rec[i - 1][0] + dp[i - 3]) % mod; } } int main(){ int t; solve(); cin >> t; while(t --){ cin >> n; cout << dp[n] * 4 % mod << endl; } return 0; }
E DeadLee(贪心+拓扑)
题意: Lee的厨房中有 n 道菜,每道菜的数量为 w[ i ] ,现在 Lee 会邀请 m 个朋友,每个朋友都有最爱吃的两道菜 x[ i ] 和 y[ i ] ,当朋友 i 来到 Lee 家后,会选择吃掉 x[ i ] 和 y[ i ] 各一份,如果 x[ i ] 没有了的话,那么他只会选择吃掉一份 y[ i ] ,如果 y[ i ] 没有了的话同理,但是如果 x[ i ] 和 y[ i ] 同时没有的话,这个朋友就会吃掉 Lee,问 Lee 能否安排一个合适的顺序以保证存活,输出这个顺序。
思路: 设 sum[ i ] 为每道菜的需求量,那么如果 sum[ i ] <= w[ i ] 的话,那么这 sum[ i ] 个人是一定可以吃到菜的,我们只需要将其安排在最后来吃就好了,同理,如果所有的 sum[ i ] > w[ i ] 成立的话,那么将会是无解的
可以使用topsort实现,把in[u] == 0 变成 need[u] <= w[u]即可。
#include<bits/stdc++.h> #define PII pair<int, int> #define x first #define y second #define ll long long using namespace std; const int N = 200010; int n,m,w[N],need[N],ans[N],idx; bool st[N], used[N]; vector<int> person[N]; PII rec[N]; bool topsort(){ queue<int> q; for(int i = 1; i <= n; ++ i) if(need[i] <= w[i]) q.push(i); while(!q.empty()){ int fr = q.front(); q.pop(); if(st[fr]) continue ; st[fr] = true; for(auto u : person[fr]){ if(used[u]) continue ; used[u] = true; ans[idx --] = u; int tmp = rec[u].x == fr ? rec[u].y : rec[u].x; need[tmp] --; if(need[tmp] <= w[tmp]) q.push(tmp); } } return idx == 0; } int main(){ cin >> n >> m; idx = m; for(int i = 1; i <= n; ++ i) scanf("%d", &w[i]); for(int i = 1; i <= m; ++ i){ int a, b; scanf("%d%d",&a,&b); need[a] ++, need[b] ++; person[a].push_back(i); person[b].push_back(i); rec[i] = {a, b}; } if(topsort()){ puts("ALIVE"); for(int i = 1; i <= m; ++ i) printf("%d ", ans[i]); } else puts("DEAD"); return 0; }