个人评论
昨天的 ABC 直接吧我打懵了,数学题多。😦
后面的两题到现在还是不会。
竞赛地址
https://atcoder.jp/contests/abc238/tasks。
A - Exponential or Quadratic
https://atcoder.jp/contests/abc238/tasks/abc238_a。
简易题解
给一个
n
n
n,问是指数函数(
2
n
2^n
2n)和一个平方函数(
n
2
n^2
n2)数据大。
如果本题
n
n
n 比较小,我们可以直接计算出结果然后比较。但是本题
n
n
n 非常大,达到
1
0
9
10^9
109,因此直接计算是不现实的。
数学上,我们知道随着
n
n
n 变大,指数函数结果肯定大于平方函数结果。
因此,我们只需要简单分类讨论一下就可以了。
- 当 n = 1 n=1 n=1 时候, 2 1 = 2 2^1=2 21=2, 1 2 = 1 1^2=1 12=1,因此指数函数大。
- 当 n = 2 n=2 n=2 时候, 2 2 = 4 2^2=4 22=4, 2 2 = 4 2^2=4 22=4,因此一样大。
- 当 n = 3 n=3 n=3 时候, 2 3 = 8 2^3=8 23=8, 3 2 = 9 3^2=9 32=9,因此平方函数大。
- 当 n = 4 n=4 n=4时候, 2 4 = 16 2^4=16 24=16, 4 2 = 16 4^2=16 42=16,因此一样大。
- 当 n = 5 n=5 n=5 时候, 2 5 = 32 2^5=32 25=32, 5 2 = 25 5^2=25 52=25,因此指数函数大。
- …
这样我们可以得出结论。
AC 代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL n;
cin>>n;
if (2<=n && n<=4) {
cout<<"No\n";
} else {
cout<<"Yes\n";
}
return 0;
}
B - Pizza
https://atcoder.jp/contests/abc238/tasks/abc238_b。
简易题解
简单的数学题。难度在于读题,英文比较菜,读了好久才读懂题目的意思。
给你
n
n
n 个切披萨的角度,问得到所有切割角度中,最大角是多少。
根据题面:rotating the pizza clockwise by
D
D
D degrees and making another cut,就是将披萨进行循环。我们可以看成将刀进行旋转,这样我们只要将切割的角度进行累加。不要忘记披萨是一个圆,只有
360
360
360 度,我们需要对
360
360
360 取模。
假设有
N
N
N 个切割角度,分别为
A
1
,
A
2
,
…
,
A
N
A_1,A_2,\dots,A_N
A1,A2,…,AN。
- 第 1 1 1 次切割,角度为 0 0 0。
- 第 2 2 2 次切割,角度为 ( 0 + A 1 ) % 360 (0+A_1) \% 360 (0+A1)%360。
- 第 3 3 3 次切割,角度为 ( 0 + A 1 + A 2 ) % 360 (0+A_1+A_2) \% 360 (0+A1+A2)%360。
- 第 4 4 4 次切割,角度为 ( 0 + A 1 + A 2 + A 3 ) % 360 (0+A_1+A_2+A_3) \% 360 (0+A1+A2+A3)%360。
- …
这样我们得到 n + 1 n+1 n+1 个角,找到这 n + 1 n+1 n+1 角度的最大值就是答案。
AC代码
标志法
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
const int N=360;
bool d[N];//false没有切割,true切割
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL n;
cin>>n;
d[0]=true;//0度切割了
LL sum=0;
for (LL i=1; i<=n; i++) {
LL x;
cin>>x;
sum=(sum+x)%360;
d[sum]=true;
}
//找连续的切割的最大角度
LL res=0;
LL cur=0;
for (LL i=0; i<=360; i++) {
if (d[i%360]) {
res=max(res, cur);
cur=0;
}
cur++;
}
cout<<res<<"\n";
return 0;
}
构造答案法
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
const int N=360;
LL ans[N];
bool d[N];//false没有切割,true切割
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL n;
cin>>n;
LL sum=0;
LL cnt=0;
ans[++cnt]=0;
for (LL i=1; i<=n; i++) {
LL x;
cin>>x;
sum=(sum+x)%360;
ans[++cnt]=sum;//送入答案数组
}
ans[++cnt]=360;
sort(ans+1, ans+cnt+1);
//找连续的切割的最大角度
LL res=0;
for (LL i=2; i<=cnt; i++) {
res=max(res, ans[i]-ans[i-1]);
}
cout<<res<<"\n";
return 0;
}
C - digitnum
https://atcoder.jp/contests/abc238/tasks/abc238_c。
简易题解
给定一个函数
f
(
x
)
f(x)
f(x),表示数位数量与
x
x
x 相同而且数据不超过
x
x
x 的正整数数量。给定一个
n
n
n,求
f
(
1
)
+
f
(
2
)
+
⋯
+
f
(
n
)
f(1)+f(2)+\dots+f(n)
f(1)+f(2)+⋯+f(n) 的值,数据对
998244353
998244353
998244353 取模。
首先。我们先看
n
n
n 的大小。本题
n
n
n 为
1
0
18
10^{18}
1018,我们没有办法根据
f
(
x
)
f(x)
f(x) 的定义直接暴力计算。但是我们要注意到
f
(
x
)
f(x)
f(x) 的定义关键数位,也就是说
1
0
18
10^{18}
1018 的数位只有
18
18
18 位。
其次。我们来分析一下
f
(
x
)
f(x)
f(x) 的属性。那就是找规律了。
- 当 x = 1 x=1 x=1 的时候,满足条件的数据只有 1 1 1,也就是 f ( 1 ) = 1 f(1)=1 f(1)=1。
- 当 x = 2 x=2 x=2 的时候,满足条件的数据只有 1 , 2 1,2 1,2,也就是 f ( 2 ) = 2 f(2)=2 f(2)=2。
- …
- 当 x = 9 x=9 x=9 的时候,满足条件的数据只有 1 , 2 , … , 9 1,2,\dots,9 1,2,…,9,也就是 f ( 9 ) = 9 f(9)=9 f(9)=9。
- 当 x = 10 x=10 x=10 的时候,满足条件的数据只有 10 10 10,也就是 f ( 10 ) = 1 f(10)=1 f(10)=1。
- 当 x = 11 x=11 x=11 的时候,满足条件的数据只有 10 , 11 10,11 10,11,也就是 f ( 11 ) = 2 f(11)=2 f(11)=2。
- …
- 当 x = 99 x=99 x=99 的时候,满足条件的数据只有 10 , 11 , … , 99 10,11,\dots,99 10,11,…,99,也就是 f ( 99 ) = 99 − 10 + 1 = 90 f(99)=99-10+1=90 f(99)=99−10+1=90。
- 当 x = 100 x=100 x=100 的时候,满足条件的数据只有 100 100 100,也就是 f ( 100 ) = 1 f(100)=1 f(100)=1。
- 当 x = 101 x=101 x=101 的时候,满足条件的数据只有 100 , 101 100,101 100,101,也就是 f ( 101 ) = 2 f(101)=2 f(101)=2。
- …
- 当 x = 999 x=999 x=999 的时候,满足条件的数据只有 100 , 101 , … , 999 100,101,\dots,999 100,101,…,999,也就是 f ( 99 ) = 999 − 100 + 1 = 900 f(99)=999-100+1=900 f(99)=999−100+1=900。
- …
那么 f ( 1 ) + f ( 2 ) + . . . f ( n ) f(1)+f(2)+...f(n) f(1)+f(2)+...f(n),我们可以根据位数分类讨论。
- 一位数。 f ( 1 ) + f ( 2 ) + . . . + f ( 9 ) = 1 + 2 + . . . + 9 f(1)+f(2)+...+f(9)=1+2+...+9 f(1)+f(2)+...+f(9)=1+2+...+9。
- 二位数。 f ( 10 ) + f ( 11 ) + . . . + f ( 99 ) = 1 + 2 + . . . + 90 f(10)+f(11)+...+f(99)=1+2+...+90 f(10)+f(11)+...+f(99)=1+2+...+90。
- 三位数。 f ( 100 ) + f ( 101 ) + . . . + f ( 999 ) = 1 + 2 + . . . + 900 f(100)+f(101)+...+f(999)=1+2+...+900 f(100)+f(101)+...+f(999)=1+2+...+900。
- 依次类图。
这样,本题根据
n
n
n 的数据范围,最多分为
18
18
18 类进行计算。
至于
f
(
x
)
f(x)
f(x) 的累加,我们可以利用等差数列求和公式计算。
AC 代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
const LL MOD=998244353;
//计算1+2+...+x
LL calc(LL x) {
x%=MOD;
LL res=x;
res=(res*(res+1)/2)%MOD;
return res;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL n;
cin>>n;
LL ans=0;
LL p10=10;
for (LL i=1; i<=18; i++) {
LL l=p10/10;//起点
LL r=min(n, p10-1);//终点
if (l<=r) {
//cout<<"calc "<<l<<" to "<<r<<"\n";
ans=(ans+calc(r-l+1))%MOD;
} else {
break;
}
p10*=10;
}
cout<<ans<<"\n";
return 0;
}
D - AND and SUM
https://atcoder.jp/contests/abc238/tasks/abc238_d。
简易题解
本题涉及到按位与运算。根据按位与的真值表,全
1
1
1 得
1
1
1。
根据题目可得:
x
+
y
=
s
,
x
and
y
=
a
x+y=s, x\ \text{and}\ y=a
x+y=s,x and y=a。
根据位运算特性,可以得知,当且仅当
s
≥
2
∗
a
s \geq 2*a
s≥2∗a,才有可能是 Yes。
AC 代码
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
using PLL=pair<LL, LL>;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL T;
cin>>T;
while (T--) {
LL a,s;
cin>>a>>s;
if (2*a<=s) {
LL t=s-2*a;
if ((t&a)==0) {
cout<<"Yes\n";
continue;
}
}
cout<<"No\n";
}
return 0;
}
E - Range Sums
https://atcoder.jp/contests/abc238/tasks/abc238_e。
简单题解
每次读入两个数据
l
,
r
l,r
l,r,最后问你所有数据是否包含
0
0
0 到
n
n
n。
本题用区间合并,DFS等方法都可以实现。
个人认为最简单的方法就是并查集。
看到包含,我们就可以使用并查集来完成。注意我们需要从
[
l
−
1
,
r
]
[l-1, r]
[l−1,r] 进行合并。合并完成后,我们查看一下
0
0
0 和
n
n
n 是否在同一个集合即可。
当然本题也可以区间合并来解决。
AC代码
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
using PLL=pair<LL, LL>;
//DSU
const int N=2e5+10;
LL fa[N];
void init(LL n) {
for (LL i=0; i<=n; i++) {
fa[i]=i;
}
}
LL find_root(LL x) {
if (fa[x]!=x) {
fa[x]=find_root(fa[x]);
}
return fa[x];
}
bool union_set(LL x, LL y) {
x=find_root(x);
y=find_root(y);
if (x==y) {
return false;
}
fa[y]=x;
return true;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL n,q;
cin>>n>>q;
init(n);//初始化并查集
while (q--) {
LL l,r;
cin>>l>>r;
union_set(l-1, r);
}
if (find_root(0)==find_root(n)) {
cout<<"Yes\n";
} else {
cout<<"No\n";
}
return 0;
}
F - Two Exams
暂时不会。
G - Cubic?
暂时也不会。