1. 比赛报告
共7题, 前3题AC, 第4题TLE, 第5题WA, 6-7题没做
本题解暂提供前5道题
2. 比赛过程
前3题 直接AC
第4,5题 暴力
3. 题解
3.1 A. How Much Does Daytona Cost?
3.1.1 题目大意:
给定有 n n n个整数组成的数组 a a a, 求是否有一个 a a a的字段, k k k在其中出现次数最多
3.1.2 当时思路:
如果
a
x
=
k
a_x = k
ax=k, 就有一个字段
[
a
x
,
a
x
]
[a_x, a_x]
[ax,ax]中
k
k
k出现次数最多, 答案是YES
否则即
a
a
a中没有
k
k
k这个元素, 答案是NO
3.1.3 题目解析:
3.1.4 AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
int t, n, k;
scanf("%d", &t);
while(t--){
bool f = 0;
int a;
scanf("%d %d", &n, &k);
while(n--){
scanf("%d", &a);
if(a == k) f = 1;
}
if(f) printf("YES\n");
else printf("NO\n");
}
return 0;
}
3.2 B. Aleksa and Stack
3.2.1 题目大意:
构造一个长度为 n n n严格递增的正整数数组, 要求每个 1 ≤ i ≤ n − 2 1 \le i \le n-2 1≤i≤n−2, a i + a i + 1 ∤ a i + 2 a_i+a_{i+1}\nmid a_{i+2} ai+ai+1∤ai+2
3.2.2 当时思路:
预处理从
1
1
1开始遍历, 如果符合要求加入
a
n
s
ans
ans数组中
每次输出数组前
n
n
n个数
3.2.3 题目解析:
奇数 + + +奇数 = = =偶数, 偶数 ∤ \nmid ∤ 奇数, 输出前 n n n个奇数
3.2.4 当时AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 2e5;
int t, n, a[N + 5];
int main(){
a[1] = 1;
a[2] = 3;
for(int i = 3, cnt = 4;i <= N;i++, cnt++){
while((3 * cnt) % (a[i-2] + a[i-1]) == 0) cnt++;
a[i] = cnt;
}
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for(int i = 1;i <= n;i++)
printf("%d ", a[i]);
printf("\n");
}
return 0;
}
至于AC代码, 你肯定会输出前 2 × 1 0 5 2\times10^5 2×105个整数
3.3 Vasilije in Cacak
3.3.1 题目大意:
给你 3 3 3个整数 n n n, k k k, x x x, 从 1 1 1到 n n n中选 k k k个整数, 和是否能等于 x x x
3.3.2 当时思路:
举个例子: n = 10 , k = 3 n=10, k=3 n=10,k=3
-
x
=
1
x = 1
x=1, 答案是
NO
, 因为最小和是 1 + 2 + 3 = 6 1+2+3 = 6 1+2+3=6 -
x
=
1
0
8
x = 10^8
x=108, 答案是
NO
, 因为最大和是 8 + 9 + 10 = 27 8+9+10 = 27 8+9+10=27
可以得到, 当
x
<
∑
1
k
x < \sum_1^k
x<∑1k或者
x
>
∑
n
−
k
+
1
n
x > \sum_{n-k+1}^n
x>∑n−k+1n时答案是NO
, 否则答案是YES
3.3.3 题目解析:
3.3.4 AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
long long t, n, k, x, y, z;
int main(){
scanf("%lld", &t);
while(t--){
scanf("%lld %lld %lld", &n, &k, &x);
y = (1 + k) * k / 2;
z = (n-k+1 + n) * k / 2;
if(y <= x && x <= z) printf("YES\n");
else printf("NO\n");
}
return 0;
}
3.4 D. Reverse Madness
3.4.1 题目大意:
输入长度为 n n n的字符串 s s s和长度为 k k k的数组 l l l和 r r r, 满足以下条件:
- l 1 = 1 , r k = n l_1 = 1, r_k = n l1=1,rk=n
- l i < r i l_i < r_i li<ri
- l i = r i − 1 + 1 l_i = r_{i-1}+1 li=ri−1+1
也就是长度为
n
n
n的字符串
s
s
s被分成
k
k
k份, 第
i
i
i段的起点和终点是
l
i
l_i
li和
r
i
r_i
ri
有
q
q
q次查询, 每次查询给一个整数
1
≤
x
≤
n
1\le x\le n
1≤x≤n, 求出所属的区间
i
i
i
把
[
min
(
x
,
l
i
+
r
i
−
x
)
,
max
(
x
,
l
i
+
r
i
−
x
)
]
\big[\min(x, l_i+r_i-x), \max(x, l_i+r_i-x)\big]
[min(x,li+ri−x),max(x,li+ri−x)]翻转
3.4.2 当时思路:
二分出 x x x所属的区间直接翻转
3.4.3 题目解析:
∵
l
i
≤
x
≤
r
i
\because l_i \le x \le r_i
∵li≤x≤ri
∴
l
i
≤
l
i
+
r
i
−
x
≤
r
i
\therefore l_i \le l_i+r_i-x \le r_i
∴li≤li+ri−x≤ri, 在区间内
x
x
x与
l
i
+
r
i
−
x
l_i+r_i-x
li+ri−x过中点相对
把
n
n
n分成
k
k
k个组, 每组统计反转次数
d
j
d_j
dj, 如果
d
j
d_j
dj是奇数, 把它与所对应的
l
i
+
r
i
−
j
l_i+r_i-j
li+ri−j交换
其他具体内容见代码
3.4.4 AC代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
const int N = 2e5 + 5;
int t, n, k, q, l[N], r[N], p[N];
int x, y, d[N];
string s;
int main(){
scanf("%d", &t);
while(t--){
memset(d, 0, sizeof(d)); //建立差分数组d
scanf("%d %d", &n, &k);
cin >> s;
for(int i = 1;i <= k;i++)
scanf("%d", &l[i]);
for(int i = 1;i <= k;i++){
scanf("%d", &r[i]);
for(int j = l[i];j <= r[i];j++){
p[j] = i; //记录i所属的区间p
}
}
scanf("%d", &q);
while(q--){
scanf("%d", &x);
y = l[p[x]] + r[p[x]] - x;
d[min(y, x)]++;
d[max(y, x)+1]--; //进行差分
}
for(int i = 1;i <= n;i++)
d[i] += d[i-1]; //求出原来交换的次数
for(int i = 1;i <= k;i++){
for(int j = l[i];j <= (l[i]+r[i])/2;j++){
if(d[j] & 1)
swap(s[j-1], s[l[i]+r[i]-j-1]);
}
}
cout << s << "\n";
}
return 0;
}
3.5 E. Iva & Pav
3.5.1 题目大意:
输入长度为 n n n的数组 a a a, f ( l , r ) = a l & a l + 1 & … & a r f(l, r) = a_l \& a_{l+1} \& \dots \& a_r f(l,r)=al&al+1&…&ar(按位与), 有 q q q次查询, 每次查询输入 l l l和 k k k, 求最大的 r r r使 f ( l , r ) ≥ k f(l, r) \ge k f(l,r)≥k
3.5.2 当时思路:
暴力
3.5.3 题目解析:
由于左端点
l
l
l和右端点
n
n
n是固定的, 可以使用二分查找最大的
r
r
r
这样就需要快速求出
f
(
l
,
r
)
f(l, r)
f(l,r), 本题不涉及修改操作, 还是一个可重复贡献问题
, 可以使用ST表
如果不了解ST表可以参考本人的另一篇文章ST表介绍, 写的不太详细, 大家多多评论
3.5.4 AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 2e5 + 5, M = 35;
int t, n, q, l, k;
int f[N][M], l2[N];
void pre(){
l2[0] = -1;
for(int i = 1;i < N;i++)
l2[i] = l2[i/2] + 1;
}
void build(){
for(int j = 1;(1 << j) <= n;j++)
for(int i = 1;i + (1 << j) - 1 <= n;i++)
f[i][j] = f[i][j-1] & f[i+(1<<j-1)][j-1];
}
int find(int l, int r){
int k = l2[r-l+1];
return f[l][k] & f[r-(1<<k)+1][k];
}
int main(){
pre();
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for(int i = 1;i <= n;i++)
scanf("%d", &f[i][0]);
build();
scanf("%d", &q);
while(q--){
scanf("%d %d", &l, &k);
if(f[l][0] < k){
printf("-1 ");
continue;
}
int L = l, R = n, r;
while(L < R){
r = (L + R + 1) / 2;
if(find(l, r) < k) R = r - 1;
else L = r;
}
printf("%d ", L);
}
}
}
4. 反思
4.1 回顾问题
不会把以前和现在的知识结合起来
4.2 如何改进
更改做题方式: 如果不会做翻翻笔记, 看看有没有可以用上的知识
这是我的帐号: I_AK-IOI
本文为可达鸭Y1第7课补题报告
感谢观看
Nov.11.2023 Sat.