本文搬运自本人初中博客园博客,若图片加载不出来,可到原文查看:https://www.cnblogs.com/zhangtingxi/p/16631668.html

比赛情况

AC:6 / 8
排名:830

题目分析

A(语法)

直接输出 sn/2+1s_{n/2+1} 即可

点击查看代码
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
// Problem: A - Middle  Letter
// Contest: AtCoder - AtCoder Beginner Contest 266
// URL: https://atcoder.jp/contests/abc266/tasks/abc266_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
//#define M
//#define mo
//#define N
int n, m, i, j, k, T;
char s[1000010];

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
scanf("%s", s+1); n=strlen(s+1);
printf("%c", s[n/2+1]);
return 0;
}

B(简单数论)

nxn-x998244353998244353 倍数,即 nx0(mod998244353)n-x\equiv 0\pmod {998244353}移项得 nx(mod998344353)n\equiv x\pmod {998344353},所以 xxnn998244353998244353 的余数

点击查看代码
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
// Problem: B - Modulo Number
// Contest: AtCoder - AtCoder Beginner Contest 266
// URL: https://atcoder.jp/contests/abc266/tasks/abc266_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
//#define M
#define mo 998244353
//#define N
int n, m, i, j, k, T;

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
n=read();
printf("%lld", (n%mo+mo)%mo);
return 0;
}


C(平面几何)

如果一个四边形是凸四边形,则必然存在一个点在另外三个点组成的三角形中

判断一个点是否在一个三角形中,只需要判断这个点和三角形三边组成的三角形面积之和是否等于大三角形面积之和,如下图

image

关于坐标系中三角形面积求法,见这里

点击查看代码
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
// Problem: C - Convex Quadrilateral
// Contest: AtCoder - AtCoder Beginner Contest 266
// URL: https://atcoder.jp/contests/abc266/tasks/abc266_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
//#define M
//#define mo
//#define N
struct node
{
int x, y;
}A, B, C, D;
int n, m, i, j, k, T;

int S(node A, node B, node C)
{
return abs((B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y-A.y));
}

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
A.x=read(); A.y=read();
B.x=read(); B.y=read();
C.x=read(); C.y=read();
D.x=read(); D.y=read();
if(S(A, B, C)==S(A, B, D)+S(A, C, D)+S(C, B, D)) return printf("No"), 0;
if(S(A, B, D)==S(A, B, C)+S(A, C, D)+S(C, B, D)) return printf("No"), 0;
if(S(A, C, D)==S(A, B, D)+S(A, B, C)+S(C, B, D)) return printf("No"), 0;
if(S(D, B, C)==S(A, B, D)+S(A, C, D)+S(C, B, A)) return printf("No"), 0;
printf("Yes");
return 0;
}

D(基础DP)

显然dp,设 dp(i,j)dp(i,j)ii 时刻在坐标 jj 的最大价值

显然因为可以从左右走过来或者不懂,所以 dp(i,j)=max(dp(i1,j1),dp(i1,j),dp(i1,j+1))dp(i,j)=\max(dp(i-1, j-1), dp(i-1, j), dp(i-1, j+1))

i=ti=t 时,dp(i,x)+=adp(i,x)+=a

初始值所有为无穷小,且 dp(0,0)=0dp(0,0)=0

代码中默认坐标+1

时间复杂度 O(n)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
48
49
50
// Problem: D - Snuke Panic (1D)
// Contest: AtCoder - AtCoder Beginner Contest 266
// URL: https://atcoder.jp/contests/abc266/tasks/abc266_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
//#define M
//#define mo
#define N 100010
int n, m, i, j, k, T;
int dp[N][10], a, t, x;

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
memset(dp, 0x80, sizeof(dp));
dp[0][1]=0;
n=read();
for(i=k=1; i<=n; ++i)
{
t=read(); x=read()+1; a=read();
while(k<=t)
{
for(j=1; j<=5; ++j)
dp[k][j]=max(dp[k-1][j], max(dp[k-1][j-1], dp[k-1][j+1]));
++k;
}
dp[t][x]+=a;
}

for(i=1; i<=5; ++i) m=max(m, dp[t][i]);
printf("%lld\n", m);
return 0;
}

E(期望DP)

f(i)f(i) 代表 ii 轮的最大期望。

考虑当前骰到 jj,该不该继续呢?

如果 j>dp(i+1)j>dp(i+1),说明继续骰期望更小,不继续,否则继续

于是可以推出式子,dp(i)=j=16max(j,dp(i+1))6dp(i)=\sum_{j=1}^6\frac{\max(j,dp(i+1))}{6}

时间复杂度 O(1)O(1)

点击查看代码
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
// Problem: E - Throwing the Die
// Contest: AtCoder - AtCoder Beginner Contest 266
// URL: https://atcoder.jp/contests/abc266/tasks/abc266_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
//#define M
//#define mo
#define N 110
int n, m, i, j, k, T;
double dp[N];

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
n=read();
for(i=n; i>=1; --i)
{
for(j=1; j<=6; ++j)
{
if(j>=dp[i+1]) dp[i]+=(double)j/6;
else dp[i]+=dp[i+1]/6;
}
}
printf("%.9lf", dp[1]);
return 0;
}

F(环套树)

题目给定的图本质上是一个树加一条边,也就是环套树,如下图所示

image

显然,两点之间的路径如果经过环则路径不唯一,因此只需要判断两点之间是否在环上即可

此处讲述一下作者复杂的实现方法:

  1. 利用并查集找出多余的那条边,O(nlogn)O(n\log n)
  2. 去掉此边dfs一遍,求出每个点的父亲节点,O(n)O(n)
  3. 暴力往上跳求出刚刚那条边连接两点lcaO(n)O(n)
  4. 标记这两点到lca的所有点,O(n)O(n)
  5. 用标记的点分别dfs,不经过环上路径O(n)O(n)
  6. 每次dfs过程中分别用并查集合并,O(nlogn)O(n\log n)
  7. 回答询问,两点在同一并查集里则方案唯一,O(q)O(q)

总复杂度 O(nlogn)O(n\log 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
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Problem: F - Well-defined Path Queries on a Namori
// Contest: AtCoder - AtCoder Beginner Contest 266
// URL: https://atcoder.jp/contests/abc266/tasks/abc266_f
// Memory Limit: 1024 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
//#define M
//#define mo
#define N 5000010
struct node
{
int x, y, n, id;
}d[N<<1];
int n, m, i, j, k, T;
int u[N], v[N], rx, ry, f[N], F[N];
int x, y, c[N], q, b[N], h[N];

void cun(int x, int y)
{
d[++k].x=x; d[k].y=y; d[k].id=i;
d[k].n=h[x]; h[x]=k;
}

int fa(int x)
{
if(x==f[x]) return x;
return f[x]=fa(f[x]);
}

void dfs(int x, int fa)
{
F[x]=fa;
int g, y;
for(g=h[x]; g; g=d[g].n)
{
y=d[g].y;
if(y==fa) continue;
if(d[g].id==i) continue;
dfs(y, x);
}
}

void DFS(int x)
{
int g, y, rx, ry;
for(g=h[x]; g; g=d[g].n)
{
y=d[g].y;
if(c[y]) continue;
// if(d[g].id==i) continue;
c[y]=1;
rx=fa(x); ry=fa(y);
f[rx]=ry; DFS(y);
}
}

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
n=read();
for(i=1; i<=n; ++i)
{
u[i]=read(); v[i]=read();
cun(u[i], v[i]); cun(v[i], u[i]);
f[i]=i;
}
for(i=1; i<=n; ++i)
{
rx=fa(u[i]); ry=fa(v[i]);
if(rx==ry) break;
else f[rx]=ry;
}
dfs(1, 0);
x=u[i]; y=v[i];
while(x) b[x]=1, x=F[x];
while(!b[y]) y=F[y];
c[y]=1;
x=u[i]; y=v[i];
while(!c[x]) c[x]=1, x=F[x];
while(!c[y]) c[y]=1, y=F[y];
for(i=1; i<=n; ++i) f[i]=i;
for(i=1; i<=n; ++i)
if(c[i]) DFS(i);
q=read();
while(q--)
{
x=read(); y=read();
rx=fa(x); ry=fa(y);
printf(rx==ry ? "Yes\n" : "No\n");
}
return 0;
}

赛后总结

惊险AC6题

开题前先去Acwing那边玩了一玩,结果罚时一大堆,rp–

开局AB很顺利,然后C卡住了,不知道怎么判凸多边形

纸上推了10分钟,推不出,上网查资料,千篇一律是三角函数,不会

终于找到一种方法,然后wa了,检查发现某个地方打错A了,卡了半小时

D一眼题,初始化那里调了一下,10分钟内过

E题看一眼就期望,随便推了小式子,5分钟内过

F题看完题后发现 nn 条边,显然环套树,然后推了推性质,代码有点长,提交后挂了

然后最后5分钟随手一拼,再交一次,A了

赛后发现是某个dfs用了全局变量,但全局变量一直在改变

终于上Cray了

晚上没力打cf了,30号看看有没有时间吧(就算有也div.4 unrated啊,呜呜)

下个月2号看看有没有时间吧

ATC正常发挥的话9月中旬能打上1300