Codeforces Round #668 (Div. 1) Solution

1405C - Balanced Bitstring

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

首先,显然 s [ i ] = s [ i − k ] = s [ i + k ] . . . s[i]=s[i-k]=s[i+k]... s[i]=s[ik]=s[i+k]...
也就是模 k k k的剩余系,都必须相同.
最后再判断一下 01 01 01个数是否超过 k / 2 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 Alice b r z brz brz在树上玩猫捉老鼠.
给定两者的初始位置和最大移动距离,然后如果 A l i c e Alice Alice b r z brz brz能出现在同一位置,那么 A l i c e Alice Alice赢,否则 b r z brz brz赢. 两个人都 绝顶 聪明, 现在你给他们当裁判.

首先,如果初始 b r z brz brz A l i c e Alice Alice的"射程"范围内,那么 A l i c e Alice Alice必胜.
否则, b r z brz brz的最优策略就是在直径上跑,只要 d b > 2 d a   & &   d b > d i a m e t e r db>2da ~\& \&~ db>diameter db>2da && db>diameter, b r z brz brz就一定能赢.
其余情况,皆为 A l i c e Alice 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 ai=i话即可删除 i i i,后面的位置顺位.
对于每个询问,我们考虑只处理 [ l , r ] [l,r] [l,r] 至多能删除多少个位置.
( n , q ≤ 1 e 5 n,q\le 1e5 n,q1e5)

首先,令 a i = i − a i a_i=i-a_i ai=iai表示前面需要删除的数的个数.
定义 f ( l , r ) f(l,r) f(l,r)表示 [ 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} f[l][r]={f[l][r1]+1f[l][r1](0a[r]f[l][r1])(else)
我们离线所有的询问,然后考虑用树状数组维护从每个位置 l l l到当前位置 r r r f ( l , r ) f(l,r) f(l,r).
容易发现 f ( l , r ) f(l,r) f(l,r)对于相同的 r r r具有单调性,所以我们每次可以在树状数组上倍增找到分界点.
然后对分界点前面的每个位置 + 1 +1 +1.
询问就是返回 f ( l , r ) 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 Alice and b r z brz brz 在玩游戏. 在给定 n n n的情况下,
A l i c e Alice Alice先把 [ 1 , 2 n ] [1,2n] [1,2n]丢到 n n n p a i r pair pair内,然后 b r z brz brz从每个 p a i r pair pair中选择一个数,
如果这些数之和可以被 2 n 2n 2n整除,那么 b r z brz brz赢.否则 A l i c e Alice Alice赢.
这是一道交互题,你可以选择做 b r z brz brz还是 A l i c e Alice Alice,但是要保证自己必胜.

容易想到这样一个构造 ( 1 , n + 1 ) , ( 2 , n + 2 ) , ( 3 , n + 3 ) . . . . . (1,n+1),(2,n+2),(3,n+3)..... (1,n+1),(2,n+2),(3,n+3).....,这样的话每个对在 m o d    n \mod n modn意义下一样.
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) sumn(n1)/22n(n1)(modn)
所以 n ∤ s u m → 2 n ∤ s u m n\not|sum\rightarrow 2n\not|sum nsum2nsum.
这种情况的条件是 2 ∣ n 2|n 2n,此时我们当 A l i c e Alice Alice必胜.

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

我们给每个环黑白染色,那么显然我们只能取一种颜色.
n ∣ n ( n − 1 ) / 2 n|n(n-1)/2 nn(n1)/2,也就是我们取一种颜色一定能搞出 n 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) sum0(mod2n) or sumn(mod2n)
此时 n ∣ ( 1 + 2 + . . . 2 n ) n|(1+2+...2n) n(1+2+...2n),所以如果 s u m ≡ n ( m o d    2 n ) sum\equiv n(\mod 2n) sumn(mod2n),我们取相反颜色即可.

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

我们一开始把所有的黑格都用 1 ∗ 1 1*1 11的覆盖,然后我们考虑把一些分割(分割表示两个 1 ∗ 1 1*1 11的格子的公共边)去掉,使得一些区域形成一个连通块.
可以发现一个不合法的区域形如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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值