Codeforces Round #668 (Div. 1) Solution

1405C - Balanced Bitstring

你有一个长度为 n n 01 01 串,其中每一个长度为 k k 的子数组中有相同的 01 01 个数.
但是这个 01 01 串被动了手脚,也就是有些位被弄成了?,你需要判断它是否能还原成一个满足上述性质的串.

首先,显然 s [ i ] = s [ i k ] = s [ i + k ] . . . s[i]=s[i-k]=s[i+k]...
也就是模 k k 的剩余系,都必须相同.
最后再判断一下 01 01 个数是否超过 k / 2 k/2 即可.

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;

int T,n,k,val[N];
char s[N];

int main() {
    cin>>T; while(T--) {
        scanf("%d %d",&n,&k);
        for(int i=0;i<k;i++) val[i]=0;
        scanf("%s",s);
        for(int i=0;i<n;i++) if(s[i]!='?') val[i%k]|=s[i]-'0'+1;
        bool flag=1; int c0=0,c1=0;
        for(int i=0;i<k;i++)
            if(val[i]==3) {flag=0; break;}
            else if(val[i]==1) c0++;
            else if(val[i]==2) c1++;
        if(!flag) {puts("NO"); continue;}
        if(c0>k/2||c1>k/2) puts("NO");
        else puts("YES");
    }
}

1405D - Tree Tag

A l i c e Alice b r z brz 在树上玩猫捉老鼠.
给定两者的初始位置和最大移动距离,然后如果 A l i c e Alice b r z brz 能出现在同一位置,那么 A l i c e Alice 赢,否则 b r z brz 赢. 两个人都 绝顶 聪明, 现在你给他们当裁判.

首先,如果初始 b r z brz A l i c e Alice 的"射程"范围内,那么 A l i c e Alice 必胜.
否则, b r z brz 的最优策略就是在直径上跑,只要 d b > 2 d a   & &   d b > d i a m e t e r db>2da ~\& \&~ db>diameter , b r z brz 就一定能赢.
其余情况,皆为 A l i c e Alice 获胜.

int n,u,v,A,B,dep[N],fa[N],f[N],c;
struct edge{int y,next; }a[N]; int len,last[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]}; last[x]=len;}
 
void dfs(int x) {
	f[x]=0;
	for(int k=last[x],y;k;k=a[k].next) 
		if((y=a[k].y)^fa[x]) {
			fa[y]=x;
			dep[y]=dep[x]+1;
			dfs(y);
			c=max(c,f[x]+f[y]+1);
			f[x]=max(f[x],f[y]+1);
		}
	c=max(c,f[x]);
}
 
int dis(int x,int y) {
	int ans=0;
	while(x^y) {
		if(dep[x]<dep[y]) swap(x,y);
		x=fa[x]; ans++;
	}
	return ans;
}
 
int main() {
	int _;qr(_); while(_--) {
		qr(n); qr(u); qr(v); qr(A); qr(B); c=0; len=0;
		for(int i=1;i<=n;i++) fa[i]=last[i]=0;
		for(int i=1,x,y;i<n;i++) qr(x),qr(y),ins(x,y),ins(y,x);
		dfs(1);
		if(dis(u,v)<=A) puts("Alice");
		else if(2*A<B&&2*A<c) puts("Bob");
		else puts("Alice"); 
	}
	return 0;
}
 

1405E - Fixed Point Removal

给定一个序列,如果 a i = i a_i=i 话即可删除 i i ,后面的位置顺位.
对于每个询问,我们考虑只处理 [ l , r ] [l,r] 至多能删除多少个位置.
( n , q 1 e 5 n,q\le 1e5 )

首先,令 a i = i a i a_i=i-a_i 表示前面需要删除的数的个数.
定义 f ( l , r ) f(l,r) 表示 [ l , r ] [l,r] 最多能删除多少个数.
那么可以得到转移方程:
f [ l ] [ r ] = { f [ l ] [ r 1 ] + 1 ( 0 a [ r ] f [ l ] [ r 1 ] ) f [ l ] [ r 1 ] ( e l s e ) f[l][r]=\begin{cases} f[l][r-1]+1&(0\le a[r]\le f[l][r-1]) \\ f[l][r-1]&(else) \end{cases}
我们离线所有的询问,然后考虑用树状数组维护从每个位置 l l 到当前位置 r r f ( l , r ) f(l,r) .
容易发现 f ( l , r ) f(l,r) 对于相同的 r r 具有单调性,所以我们每次可以在树状数组上倍增找到分界点.
然后对分界点前面的每个位置 + 1 +1 .
询问就是返回 f ( l , r ) f(l,r) 啦~.

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator 
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=3e5+10,size=1<<20,mod=998244353,inf=2e9;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
    char c=gc; x=0; int f=1;
    while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
    while(isdigit(c)) x=x*10+c-'0',c=gc;
    x*=f;
}
template<class o> void qw(o x) {
    if(x/10) qw(x/10);
    putchar(x%10+'0');
}
template<class o> void pr1(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar('\n');
}

int n,q,a[N],c[N],ans[N];
vector<pii> b[N];
//树状数组维护以每个位置开头的最多删除数量

void add(int x,int d) {for( ;x<=n;x+=x&-x) c[x]+=d; }
int ask(int x) {int y=0; for(;x;x-=x&-x) y+=c[x]; return y;}

int main() {
    qr(n); qr(q);
    for(int i=1;i<=n;i++) qr(a[i]);
    for(int i=1,l,r;i<=q;i++) qr(l),qr(r),b[n-r].pb(mk(l+1,i));
    for(int i=1;i<=n;i++) {
        a[i]=i-a[i];
        if(a[i]>=0) {
            int x=0;
            for(int s=0,j=21;j>=0;j--)
                if(x+(1<<j)<=i&&s+c[x+(1<<j)]>=a[i]) 
                    {x+=1<<j; s+=c[x];}
            add(1,1); add(x+1,-1);
        }
        for(auto p:b[i]) ans[p.se]=ask(p.fi);
    }
    for(int i=1;i<=q;i++) pr2(ans[i]);
    return 0;
}

1404D - Game of Pairs

A l i c e Alice and b r z brz 在玩游戏. 在给定 n n 的情况下,
A l i c e Alice 先把 [ 1 , 2 n ] [1,2n] 丢到 n n p a i r pair 内,然后 b r z brz 从每个 p a i r pair 中选择一个数,
如果这些数之和可以被 2 n 2n 整除,那么 b r z brz 赢.否则 A l i c e Alice 赢.
这是一道交互题,你可以选择做 b r z brz 还是 A l i c e Alice ,但是要保证自己必胜.

容易想到这样一个构造 ( 1 , n + 1 ) , ( 2 , n + 2 ) , ( 3 , n + 3 ) . . . . . (1,n+1),(2,n+2),(3,n+3)..... ,这样的话每个对在 m o d    n \mod n 意义下一样.
s u m n ( n 1 ) / 2 n 2 ( n 1 ) ( m o d    n ) sum\equiv n(n-1)/2\equiv \dfrac n 2\cdot (n-1)(\mod n)
所以 n ∤ s u m 2 n ∤ s u m n\not|sum\rightarrow 2n\not|sum .
这种情况的条件是 2 n 2|n ,此时我们当 A l i c e Alice 必胜.

否则,我们令同 p a i r pair 的数连边,同时连 ( i , i + n ) ( i [ 1 , n ] ) (i,i+n)(\forall i\in [1,n]) .
此时我们可以连出这样的一张图(这是一个 n = 5 n=5 的情况),图由若干个长度为偶数的环组成.
在这里插入图片描述

我们给每个环黑白染色,那么显然我们只能取一种颜色.
n n ( n 1 ) / 2 n|n(n-1)/2 ,也就是我们取一种颜色一定能搞出 n n 的倍数,所以选出来 s u m 0 ( m o d    2 n )   o r   s u m n ( m o d    2 n ) sum\equiv 0(\mod 2n) ~or ~ sum\equiv n(\mod 2n)
此时 n ( 1 + 2 + . . . 2 n ) n|(1+2+...2n) ,所以如果 s u m n ( m o d    2 n ) sum\equiv n(\mod 2n) ,我们取相反颜色即可.

int n,col[N],pos[N];
vi p[N];
ll s[5];

void dfs(int x,int c) {
    if(col[x]>=0) return ;
    col[x]=c; s[c]+=x; c^=1;
    if(x<=n) dfs(x+n,c);
    else dfs(x-n,c);
    dfs(p[pos[x]][0],c);
    dfs(p[pos[x]][1],c);
}

int main() {
    qr(n);
    if(n%2==0) {
        puts("First");
        for(int i=0;i<2*n;i++) pr1(i%n+1);
        return 0;
    }
    puts("Second"); fflush(stdout);
    for(int i=1,x;i<=n*2;i++) qr(x),pos[i]=x,p[x].pb(i),col[i]=-1;
    for(int i=1;i<=n*2;i++) dfs(i,0);
    int t=(s[0]%(2*n))?1:0;
    for(int i=1;i<=n*2;i++) if(col[i]==t) pr1(i);
    return 0;
}

1404E - Bricks

b r z brz 要求装修工 l z y lzy 铺一个 n m n*m 的地板,有些格子是黑色,有些格子是白色.
l z y lzy 只有宽为1的砖(只能横竖放置).
b r z brz 有一个严苛的要求: 只能用砖覆盖黑色格子,且每个格子只能被一个砖覆盖.同时最小化用的砖数.

我们一开始把所有的黑格都用 1 1 1*1 的覆盖,然后我们考虑把一些分割(分割表示两个 1 1 1*1 的格子的公共边)去掉,使得一些区域形成一个连通块.
可以发现一个不合法的区域形如L形. 也就是有些分割不能同时被去掉.
左右的分割和上下的分割内部不连边,也就是个二分图.
所以我们只要求出二分图的最大独立集即可.

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator 
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=8e4+10,M=210,size=1<<20,mod=998244353,inf=2e9;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
    char c=gc; x=0; int f=1;
    while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
    while(isdigit(c)) x=x*10+c-'0',c=gc;
    x*=f;
}
template<class o> void qw(o x) {
    if(x/10) qw(x/10);
    putchar(x%10+'0');
}
template<class o> void pr1(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar('\n');
}

int n,m,U[M][M],L[M][M],tot,st,ed;
char s[M][M];
struct edge{int y,next,c; } a[N*6]; int len=1,last[N],cur[N];
void ins(int x,int y,int c) {a[++len]=(edge){y,last[x],c}; last[x]=len; }
void add(int x,int y,int c) {ins(x,y,c); ins(y,x,0);}

int d[N],q[N];
bool bfs() {
    for(int i=1;i<=ed;i++) d[i]=0,cur[i]=last[i];
    int l,r; q[l=r=1]=st; d[st]=1;
    for(int x=st;l<=r;x=q[++l])
        for(int k=last[x],y;k;k=a[k].next)
            if(!d[y=a[k].y]&&a[k].c) d[y]=d[x]+1,q[++r]=y;
    return d[ed];
}

int dfs(int x,int f) {
    if(x==ed) return f;
    int s=0,t;
    for(int &k=cur[x],y,z;k;k=a[k].next) {
        y=a[k].y; z=min(a[k].c,f-s);
        if(d[y] == d[x] + 1 && z) {
            s += t = dfs(y,z);
            a[k].c -= t;
            a[k^1].c += t;
            if(s == f) return f;
        }
    }
    if(!s) d[x]=0;
    return s;
}

int dicnic() {
    int ans=0;
    while(bfs()) ans += dfs(st,inf);
    return ans;
}

int main() {
    qr(n); qr(m); int ans=0;
    for(int i=1;i<=n;i++) {
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;j++)
            if(s[i][j]=='#') {
                ans++; 
                if(s[i-1][j]=='#') U[i][j]=++tot,ans--;
                if(s[i][j-1]=='#') L[i][j]=++tot,ans--;
            }
    }
    st = ++tot; ed = ++tot;
    const int dx[]={1,1,0,0},dy[]={0,-1,0,-1};
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) {
            int x=L[i][j];
            if(U[i][j]) add(U[i][j],ed,1);
            if(!x) continue;
            add(st,x,1); 
            for(int t=0;t<4;t++) {
                int tx=i+dx[t],ty=j+dy[t];
                if(U[tx][ty]) add(x,U[tx][ty],1);
            }
        }
    pr2(ans+dicnic()); return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/108445867