1405C - Balanced Bitstring
你有一个长度为 的 串,其中每一个长度为 的子数组中有相同的 个数.
但是这个 串被动了手脚,也就是有些位被弄成了?
,你需要判断它是否能还原成一个满足上述性质的串.
首先,显然
也就是模
的剩余系,都必须相同.
最后再判断一下
个数是否超过
即可.
#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
和 在树上玩猫捉老鼠.
给定两者的初始位置和最大移动距离,然后如果 和 能出现在同一位置,那么 赢,否则 赢. 两个人都 绝顶 聪明, 现在你给他们当裁判.
首先,如果初始
在
的"射程"范围内,那么
必胜.
否则,
的最优策略就是在直径上跑,只要
,
就一定能赢.
其余情况,皆为
获胜.
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
给定一个序列,如果 话即可删除 ,后面的位置顺位.
对于每个询问,我们考虑只处理 至多能删除多少个位置.
( )
首先,令
表示前面需要删除的数的个数.
定义
表示
最多能删除多少个数.
那么可以得到转移方程:
我们离线所有的询问,然后考虑用树状数组维护从每个位置
到当前位置
的
.
容易发现
对于相同的
具有单调性,所以我们每次可以在树状数组上倍增找到分界点.
然后对分界点前面的每个位置
.
询问就是返回
啦~.
#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
and 在玩游戏. 在给定 的情况下,
先把 丢到 个 内,然后 从每个 中选择一个数,
如果这些数之和可以被 整除,那么 赢.否则 赢.
这是一道交互题,你可以选择做 还是 ,但是要保证自己必胜.
容易想到这样一个构造
,这样的话每个对在
意义下一样.
所以
.
这种情况的条件是
,此时我们当
必胜.
否则,我们令同
的数连边,同时连
.
此时我们可以连出这样的一张图(这是一个
的情况),图由若干个长度为偶数的环组成.
我们给每个环黑白染色,那么显然我们只能取一种颜色.
,也就是我们取一种颜色一定能搞出
的倍数,所以选出来
此时
,所以如果
,我们取相反颜色即可.
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
要求装修工 铺一个 的地板,有些格子是黑色,有些格子是白色.
只有宽为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;
}