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[i−k]=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,q≤1e5)
首先,令
a
i
=
i
−
a
i
a_i=i-a_i
ai=i−ai表示前面需要删除的数的个数.
定义
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][r−1]+1f[l][r−1](0≤a[r]≤f[l][r−1])(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)
sum≡n(n−1)/2≡2n⋅(n−1)(modn)
所以
n
∤
s
u
m
→
2
n
∤
s
u
m
n\not|sum\rightarrow 2n\not|sum
n∣sum→2n∣sum.
这种情况的条件是
2
∣
n
2|n
2∣n,此时我们当
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
n∣n(n−1)/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)
sum≡0(mod2n) or sum≡n(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)
sum≡n(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 n∗m的地板,有些格子是黑色,有些格子是白色.
l z y lzy lzy只有宽为1的砖(只能横竖放置).
b r z brz brz有一个严苛的要求: 只能用砖覆盖黑色格子,且每个格子只能被一个砖覆盖.同时最小化用的砖数.
我们一开始把所有的黑格都用
1
∗
1
1*1
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;
}