情况

时间:2024年7月2日 星期二 16:25
完成情况:
只过了A····
B题TLE,第一个样例都没过。
C题卡在test 10 TLE。
总体表现很糟糕。

题解

A - Soccer

题意

分析分心前比分和之后的比分,看这两个比分中途有没有可能两边产生打平的情况。

思路

比较简单,观察规律得只要有反超的情况,就一定会打平,直接if判断。

B - Collatz Conjecture

题意

有一个变量 x 和一个常数 y。执行 k 次以下操作次数:

  • x 增加 1
  • 判断数字 x 能被整 y 除时,将其除以 y 。能除一直除

两个操作是算一次。
输出最后的x的值

思路

有数学原型的题目。

根据题干和范围,这题肯定要用到数学知识。
有如下规律,当x到达1后,后面的操作就是一样的,将x加到y,然后又变为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
44
45
46
47
48
49
50
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <sstream>
#include <iomanip>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 100000;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--)
{
LL x, y, k;
cin >> x >> y >> k;
do
{
LL noww = x / y;
LL target = (noww + 1) * y;
if (k+x <= target )
{
x += k;
k = 0;
}
else{
k -= target - x;
x = target;
}
while(x%y==0){
x = x / y;
}

} while (k > 0 && x> 1);
if(x==1){
k %= (y - 1); // 这里,出错!数学要严谨!
x += k;
}
cout << x << endl;
}

return 0;
}

问题

这题真是狼狈。
比赛时候,理解题目意思,就花了20分钟,一直纠结一次到底要做什么。
然后写代码,第一个样例过不了TLE。原因是全模拟了,没有用数学。
对着TLE思考,“这题应该得用数学吧”,结果写不出数学。因为前半段完全可以用模拟。
赛后补题,知道后半段要用数学,结果tmd直接拿x+k来模y,殊不知k每次减少的是4。这属实是凭感觉写了。
总结:模拟和数学结合!数学要弄明白了再写。
这里放tourist三分钟ac警示自己:

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
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int x, y, k;
cin >> x >> y >> k;
while (k > 0 && x > 1) {
int rm = x % y;
if (rm < y - 1) {
int take = min(y - 1 - rm, k);
x += take;
k -= take;
continue;
}
x += 1;
while (x % y == 0) {
x /= y;
}
k -= 1;
}
if (k > 0) {
assert(x == 1);
x = k % (y - 1) + 1;
}
cout << x << '\n';
}
return 0;
}

C - Boring Day

题意

有一副牌n张, 从顶部开始的第 i 张牌上写着一个数字 $a_i$。在每个回合中,他从牌组顶部取出非零数量的牌并完成该回合。如果在回合中收集到的牌上的数字之和介于左边界 l 和右边界 r 之间,则赢得该回合;否则,弃牌。
输出赢的回合总数。
给出n,l,r 和$a_i$:

1
2
5 3 10
2 1 11 3 7

上面用例2 1 ,3 ,7为赢的回合取的牌。答案为3

思路

贪心,双指针
从前往后取牌,计算sum

  1. 小于左边界,继续取,右指针继续往前,sum加上
  2. 大于右边界,左指针往前一格就行了,sum减去,相当于从多的开始找到1或3状态。
  3. 在左右之间,则能赢这回合,左右指针从右指针位置,开始新的回合。

代码

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
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <sstream>
#include <iomanip>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 100001;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;

while (t--)
{

LL n, l, r;
cin >> n >> l >> r;
LL num[N] = {0};
LL sum[N] = {0};
for (int i = 1; i <= n; ++i)
{
cin >> num[i];
sum[i] = sum[i - 1] + num[i];
}
LL p1 = 1, p2 = 1;LL ans = 0;
while (p1 <=n)
{
LL temp = sum[p2] - sum[p1 - 1];
if (temp >= l && temp <= r)
{
ans++;
p1 = p2 + 1;
}
else if (temp > r)
{
p1++;
continue;
}
if(p2<n)p2++;
else
p1++;
}
cout << ans << endl;
}
return 0;
}

问题

这题比赛时候,在中途TLE;之后补题还TLE,从test 10 wa变成了test 17 wa,原因是:
以为自己用的是双指针,不过双的不够彻底!
特别是小于左边界那一块,只需动左指针就行了,因为如果动右指针还需重复计算,以为回归到左指针位置,还可能有一个牌赢得回合的可能,实际上,因为你超过的时候是一个边界状态,边界之前的情况都是小的,移动左指针更小,就不用重复计算。
比赛时候也是没想明白,并且还没有重复利用变量。

D

虽然看了题解,但是不想补了,构造题搭配gcd,以后巩固gcd时候再看一看。