Educational Codeforces Round 128 (Rated for Div. 2)
险些三题选手身败名裂。幸好 E 太水了。
CF1680A Minimums and Maximums
不会,略。
CF1680B Robots
不会,略。
CF1680C Binary String
0 不减少,答案就不会变小。假设现在有 \(x\) 个 \(0\)。
那么我删去了 \(y\) 个 \(0\) ,那么我删去 \(x - y\) 个 \(1\) 也不会让我的答案变大。
因此发现,我可以钦定我删去 \(x\) 个数,那么一定可以得到最优答案。
枚举开头删多少个就可以了。
CF1680D Dog Walking
注意到我们需要求到到达位置的最大值和最小值。
为了达到最大值,我们可以一直放 \(k\) ,为了到最小值一直放 \(-k\)。
可不可行就看我后面的空白一直填 \(k\) 或 \(-k\) 使得我的区间跨过 \(0\)。
我们可以枚举我们的最大值在什么时候取到,枚举最小值在什么时候取到。在取到最大值之前我们一直用 \(k\) ,然后一直取 \(-k\)。
检查能否成功结束。
int main() {
read(n),read(k);
for (int i = 1; i <= n; ++i) read(a[i]) , v[i] = v[i - 1] + a[i];
for (int i = 1; i <= n; ++i) pre[i] += pre[i - 1] + (a[i] == 0);
if(v[n] + pre[n] * k < 0 || v[n] - pre[n] * k > 0) {
puts("-1");
return 0;
}
LL ans = 0;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= n; ++j) if(i != j) {
if(i < j) {
int t = pre[j] - pre[i];
ans = max(ans , min(t * k , v[n] + (pre[n] - t) * k) + v[i] - v[j] + 1);
}
else {
int t = pre[i] - pre[j];
ans = max(ans , min(t * k , -(v[n] - (pre[n] - t) * k)) + v[i] - v[j] + 1);
}
}
write(ans);
return 0;
}
CF1680E Moving Chips
真的很简单。最后只有一个薯片。
所以左右交汇。定义 \(f_{i,0/1}\) 表示左边 \(i\) 个合在上/下面。
定义 \(g_{i , 0/1}\) 同理。枚举合并位置即可。
int n , f[MAXN][2] , g[MAXN][2] , pt[MAXN] , st[MAXN];
char s[2][MAXN];
int main() {
int T;
read(T);
while(T -- > 0) {
read(n);
scanf("%s" , s[0] + 1);
scanf("%s" , s[1] + 1);
int ty = 0;
for (int i = 1; i <= n; ++i) {
if(!ty) {
f[i][0] = (s[1][i] == '*');
f[i][1] = (s[0][i] == '*');
}
else {
f[i][0] = min(f[i - 1][1] + 2 , f[i - 1][0] + 1 + (s[1][i] == '*'));
f[i][1] = min(f[i - 1][0] + 2 , f[i - 1][1] + 1 + (s[0][i] == '*'));
}
ty |= (s[1][i] == '*' || s[0][i] =='*');
pt[i] = ty;
}
ty = 0;
st[n + 1] = 0;
for (int i = n; i >= 1; --i) {
if(!ty) {
g[i][0] = (s[1][i] == '*');
g[i][1] = (s[0][i] == '*');
}
else {
g[i][0] = min(g[i + 1][1] + 2 , g[i + 1][0] + 1 + (s[1][i] == '*'));
g[i][1] = min(g[i + 1][0] + 2 , g[i + 1][1] + 1 + (s[0][i] == '*'));
}
ty |= (s[1][i] == '*' || s[0][i] =='*');
st[i] = ty;
}
int ans = 1e9;
for (int i = 0; i <= n; ++i) {
ans = min(ans , min(f[i][0] + g[i + 1][0] , f[i][1] + g[i + 1][1]) + 1 * pt[i] * st[i + 1]);
}
write(ans);
}
return 0;
}
CF1680F Lenient Vertex Cover
这种题,我们一般立足于 dfs 树分析。
如果 dfs 树上通过返祖边只能得到偶环,那么说明是二分图,直接染色就好了。
如果只有一个返祖边构成的奇环,那么图上所有奇环都经过返祖边,钦定这条边上两个点颜色一样染色即可。
如果有多个返祖边构成的奇环,那么我们需要找到一条边,使得这条边被所有这样的奇环包含并且不被任何一条偶环包含。
因为如果被奇环和偶环同时包含,那就必然存在不经过它的奇环。找到了钦定边上两点颜色再染色就好。
#include <map>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define pii pair <int , int>
#define mp make_pair
#define fs first
#define sc second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
template <typename T>
void read(T &x) {
x = 0;T f= 1;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s^'0');s=getchar();}
x *= f;
}
template <typename T>
void write(T x , char s='\n') {
if(!x) {putchar('0');putchar(s);return;}
if(x<0) {putchar('-');x=-x;}
int tmp[25] = {} , t = 0;
while(x) tmp[t ++] = x % 10 , x /= 10;
while(t -- > 0) putchar(tmp[t] + '0');
putchar(s);
}
const int MAXN = 2e6 + 5;
int n , m , head[MAXN] , to[MAXN << 1] , nxt[MAXN << 1] , cnt , edge[MAXN << 1] , fl[MAXN << 1];
void add(int u , int v) {nxt[++cnt] = head[u];head[u] = cnt;to[cnt] = v;}
int odd , nud[MAXN] , nue[MAXN] , dfn[MAXN] , num , dep[MAXN];
pii tmp;
void dfs(int x , int fa) {
dfn[x] = ++num;
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if(v == fa) continue;
if(dfn[v]) {
if(dfn[v] > dfn[x]) continue;
if((dep[x] - dep[v] + 1) & 1) {
odd ++;tmp = mp(x , v);
nud[x] ++ , nud[v] --;
}
else {
nue[x] ++ , nue[v] --;
}
}
else {
dep[v] = dep[x] + 1;
dfs(v , x);
edge[i] += nud[v];
if(nue[v]) fl[i] = 1;
nud[x] += nud[v] , nue[x] += nue[v];
}
}
}
int vis[MAXN];
void find(int x) {
if(vis[x]) return;
vis[x] = 1;
// cerr << x << endl;
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if(dfn[v] < dfn[x]) continue;
if(!fl[i] && edge[i] == odd) {
tmp = mp(x , v);
break;
}
find(v);
if(tmp.fs != -1) break;
}
}
int col[MAXN];
void calc(int x) {
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if(!col[v]) {
col[v] = -col[x];
calc(v);
}
}
}
int main() {
// freopen("1.in" , "r" , stdin);
// freopen("1.out" , "w" , stdout);
int T;
read(T);
while(T -- > 0) {
read(n),read(m);
for (int i = 1; i <= m; ++i) {
int u , v;
read(u),read(v);
add(u , v) , add(v , u);
}
tmp = mp(-1 , -1);
dfs(1 , 0);
if(!odd) {
col[1] = 1;
calc(1);
puts("YES");
for (int i = 1; i <= n; ++i) {
if(col[i] == 1) putchar('1');
else putchar('0');
}
puts("");
}
else if(odd == 1) {
col[tmp.fs] = col[tmp.sc] = 1;
calc(tmp.fs) , calc(tmp.sc);
puts("YES");
for (int i = 1; i <= n; ++i) {
if(col[i] == 1) putchar('1');
else putchar('0');
}
puts("");
}
else {
tmp = mp(-1 , -1);
find(1);
if(tmp.fs == -1) puts("NO");
else {
puts("YES");
col[tmp.fs] = col[tmp.sc] = 1;
calc(tmp.fs) , calc(tmp.sc);
for (int i = 1; i <= n; ++i) {
if(col[i] == 1) putchar('1');
else putchar('0');
}
puts("");
}
}
for (int i = 1; i <= cnt; ++i) fl[i] = edge[i] = 0;
num = odd = cnt = 0;
for (int i = 1; i <= n; ++i) head[i] = 0 , col[i] = 0 , dfn[i] = dep[i] = nud[i] = nue[i] = 0 , vis[i] = 0;
}
return 0;
}