CF global round 29
C
思路:
只要考虑每个 0 的位置怎么更新
考虑从当前 pos[i] 转移到下一个 pos[i+1] 的位置
分三种情况,
中间没有 1, 只要当前位置有一个位置左右两种情况都能转移
中间 1 个 1, 必须让左右两个 0,看向中间这个 1 才行
中间 1 的数量 > 1, 强制前一个0向左,后一个 0 向右才可行
再考虑初始化和最终状态的结果情况,就是看要不要强制方向
初始化第一个 0,左边有 1,就必须向右看
最后一个0,后面有 1,就必须向左看,答案就是 dpL
否则两边都可行,答案就是 dpL | dpR
代码:
void Solve(){
cin >> n >> s, s = " " +s;
vector<int> pos;
For(i,1,n) if(s[i] == '0') pos.pb(i);
if(pos.empty()) return puts("YES"), void();
m = pos.size();
vector<int> dp0(m), dp1=dp0;
int i0 = pos[0];
if(i0 > 1 && s[i0-1] == '1'){
dp1[0] = 1;
}else{
dp0[0] = dp1[0] = 1;
}
for(int i=0;i<m-1;++i){
l = pos[i], r = pos[i+1];
int mid = r-l-1, ndp0 = 0, ndp1 = 0;
if(mid == 0){
if(dp0[i] || dp1[i]) ndp0 = ndp1 = 1;
}else if(mid == 1){
if(dp0[i]) ndp1 = 1;
if(dp1[i]) ndp0 = 1;
}else{
if(dp0[i]) ndp1 = 1;
}
dp0[i+1] = ndp0, dp1[i+1] = ndp1;
}
bool ok = 0;
int ik = pos.back();
if(ik<n && s[ik+1] == '1'){
ok |= dp0[m-1];
}else{
ok |= (dp1[m-1] || dp0[m-1]);
}
puts(ok?"YES":"NO");
}
D
这个是SB题吧,什么东西啊看,比A还简单啊
这个场到底什么难度
就肯定是选频次最多的,然后奇数换先手,完了,后手不跟必挂
void Solve(){
cin >> n;
map<int,int> cnt;
For(i,1,n) cin >> x, cnt[x]++;
vector<pii> todo;
for(auto [num,cc] : cnt) todo.emplace_back(num,cc);
sort(all(todo), [&](pii a,pii b){
if(a.second == b.second) return a.first > b.first;
return a.second > b.second;
});
ll ans[2]{}, now = 0;
for(auto [x, ncnt] : todo){
ans[now] += 1ll * (x+1)/2 * ncnt, ans[now^1] += 1ll * x/2 * ncnt;
if(x&1) now ^= 1;
}
cout << ans[0] << ' ' << ans[1] << '\n';
}

浙公网安备 33010602011771号