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;
}
京公网安备 11010502036488号