Codeforces Round #516[CF1063]

Codeforces Round #516

A

题意:重排字符串,使得字符串的回文子串个数最多。输出任意一个满足条件的字符串。

找规律发现,将字符从小到大排好就是一个满足条件的字符串。

考虑一个字母,它出现了 $x$ 遍,那么由这个字母结尾的回文串最多只有 $\frac{x(x+1)}{2}$ 个,而排序则刚好达到这个上界。

因此上面那个规律就是正确的了。

B

题意:$n\times m$ 个格子,某些格子是障碍物。从某一个点出发,向左不能超过 $L$ 次,向右不能超过 $R$ 次,问能到达的点的个数。

一看上去它有两个限制条件,非常不好做,如果只剩一个那就可以随便bfs了。

首先,假设你从 $(x,y)$ 出发,要到达 $(x_0,y_0)$,假设你向左走了 $l$ 步,那么你显然是向右走了 $l+(y_0-y)$ 步。

因此,只需要最小化其中任意一个限制就可以了。

剩下就是一个简单的 bfs。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cout<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const int N=2005;
int n,m,max_le,max_ri,ans;
struct node{
int x,y,l,r;
};
queue<node> q;
bool vis[N][N];
inline void update(node u)
{
node v;
for(v=u,v.x--;;v.x--)
{
if(v.x<=0||vis[v.x][v.y]) break;
vis[v.x][v.y]=1;
q.push(v);
ans++;
}
for(v=u,v.x++;;v.x++)
{
if(v.x>n||vis[v.x][v.y]) break;
vis[v.x][v.y]=1;
q.push(v);
ans++;
}
}
inline void Left(node u)
{
if(u.l>=max_le) return;
u.y--; u.l++;
if(u.y<=0||vis[u.x][u.y]) return;
vis[u.x][u.y]=1;
ans++;
q.push(u);
update(u);
}
inline void Right(node u)
{
if(u.r>=max_ri) return;
u.y++; u.r++;
if(u.y>m||vis[u.x][u.y]) return;
vis[u.x][u.y]=1;
ans++;
q.push(u);
update(u);
}
char s[N];
int main()
{
n=read(); m=read();
int nx=read(),ny=read();
max_le=read(); max_ri=read();
fo(i,1,n)
{
scanf("%s",s+1);
fo(j,1,m) vis[i][j]=(s[j]=='*');
}
if(vis[nx][ny]==1) return puts("0");
q.push((node){nx,ny,0,0});
vis[nx][ny]=1; update((node){nx,ny,0,0});
ans++;
for(;!q.empty();)
{
node u=q.front(); q.pop();
Left(u); Right(u);
}
printf("%d",ans);
return 0;
}

C

题意:交互题,问交互器 $n$ 遍,每次你可以询问一个点是黑色还是白色,最后让你求出一条直线,使得该直线将询问的 $n$ 个点分成两部分,每部分颜色相同,两部分颜色不同。

$n\leq 30$,$0\leq x,y \leq 10^9$。

可以发现,$\log_2{10^9}\approx 30$,考虑二分。

实际上二维是假的,我们只需要考虑一条直线上的点,最后再用一条斜斜的直线截成两部分就好了。

枚举 $[l,r]$ 的中间点 $mid$,问它是否是白色还是黑色就好了。

时间复杂度 $O(n)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cout<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
int n;
char s[10];
inline bool ask(int x,int y)
{
printf("%d %d\n",x,y);
fflush(stdout);
scanf("%s",s);
return s[0]=='b';
}
int main()
{
scanf("%d",&n);
int l=0,r=1e9,mid;
bool b=ask(0,1),t;
ff(i,1,n)
{
mid=l+r>>1;
if(ask(mid,1)==b) l=mid; else r=mid;
}
printf("%d %d %d %d",l,0,l+1,2);
return 0;
}

D

题意:一个圆环上 $n$ 个人,$k$ 个糖果。你可以设定每个人每次最多拿走 $1$ 个或 $2$ 个糖果,从 $l$ 开始顺时针让人拿糖果,最后在 $r$ 时糖果没了。如果还有糖果则这个人能要拿最多的,但不能超出限制。最大化最多拿两个糖果的人数。$n,l,r,k\leq 10^{11}$。

数据分治,然后列出一大堆不等式,讨论一下注意细节就好了。

F

黑红兔[FJWC2020Day1]