SDNU_ACM_ICPC_2019_Winter_Practice_1st题解报告
这几天四处去过年,闲下来建博客,抽时间打比赛,现在终于建立好了博客,也到快到大年三十了,终于闲下来可以理理题解发发博文了。 我t喵的建好了博客,想什么时候提交博文就什么时候提交,csdn再贱!
这是寒假第一场,,有些没回过来,,,放纵自己的后果,,就是比赛只能三题下场,,
A - The kth great number
题意:找出第k大数,输入n和k,之后n行输入,前缀为Q输出第k大数,前缀为I输入数据进入队列
题解:这题证明我还没熟练stl,,,第一下想到的是数组,用数组模拟一下也能出来,就是麻烦 当时模拟出来了,,但是没看到题干的多组数据输入,就一直w,, 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
using namespace std;
int nn[1000010];
bool cmpp(int a, int b)
{
return a > b;
}
int main()
{
int n, k;
while(~scanf("%d%d", &n, &k)){
for(int i = 0; i < n; i++){
char aim;
int num;
cin>> aim;
if(aim == 'I')scanf("%d", &num);
if(i == k)sort(nn, nn + k, cmpp);//凑满k个数后sort一下,然后就从第k个替换就行
switch(aim){
case 'I':if(i < k)nn[i] = num;
else {
if(num <= nn[k - 1])continue;
else {
nn[k - 1] = num;
for(int j = k - 1; j >= 1; j--){
if(nn[j] > nn[j - 1])
{
int t = nn[j];
nn[j] = nn[j - 1];
nn[j - 1] = t;
}
else break;
}
}
}
break;
case 'Q':
cout<< nn[k - 1] <<'\n';
}
}
}
return 0;
}
用上stl后便能简便解决了,用lower函数找到输入数字应该在的地方插进去就行 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
using namespace std;
int main()
{
int n, k;
while(~scanf("%d%d", &n, &k)){
vector<int>v;
while(n--){
char aim;
cin>> aim;
if(aim == 'I'){
int num;
scanf("%d", &num);
int pla = lower_bound(v.begin(), v.end(), num) - v.begin();
v.insert(v.begin() + pla, num);
}
else {
printf("%d\n", v[v.size() - k]);
}
}
}
return 0;
}
题意:问有哪些数的阶乘末尾有m个0,输入m,输出总共有几个数达到要求,再输出是哪几个数
题解:数的阶乘:n! = n(n-1)(n-2)...21 阶乘有几个零和阶乘中出现了几个5有关,且25 == 155, 50 == 255, 从1往后数每五个数出现一个5, 每55个数出现两个五,以此类推,所以 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
using namespace std;
int five(int n)
{
int q = 0;
while(n){
q += n / 5;
n /= 5;
}
return q;
}
int main()
{
int n;
scanf("%d", &n);
int i = 5, t;
while(1){
t = five(i);
if(t >= n)break;
i += 5;
}
if(t == n){
puts("5");
printf("%d", i);
for(int j = 0; j < 4; j++)printf(" %d", ++i);
}
else puts("0");
return 0;
}
## C - New Skateboard CodeForces - 628B | ||
题意:输入一个数字字符串,求其中有多少个能被四整除的连续子串 ### 参考资料:整除规则(原理,性质) | ||
题解:根据参考资料, 一个整数的末尾两位数能被4整除则这个数能被4整除,单独判断第一个数能否被四整除,如果能本身就作为一个子串加一,之后除了单独判断当前数本身, 再判断i - 1的数和当前位i组成的两位数能否被四整除,如果能,加上前面那些数就能组成i个能被四整除的字串,还有一个坑就是这道题数据很多,得用longlong,,
|
D - Color the ball
题意:给n个气球, 再有n行输入数据,分别为a和b,每行把气球编号a到b都涂一次色,问最后每个气球被涂色的次数
题解:把区间左端加一,右端外面减一,输出时从左段加到右端,边加边输出,正解Albert_s说是线段树,muyu_说是差分,只有我什么都不会,,那我去把这两个都学了吧,, 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
using namespace std;
int ball[100100];
int main()
{
int t;
while(~scanf("%d", &t) && t != 0){
memset(ball, 0, sizeof(ball));
int a, b;
for(int jj = 0; jj < t; jj++){
scanf("%d%d", &a, &b);
++ball[a], --ball[b + 1];
}
for(int i = 1; i <= t; i++){
if(i != 1)putchar(' ');
printf("%d", ball[i] += ball[i - 1]);
}
putchar('\n');
}
return 0;
}
E - 非常可乐
题意:裸bfs题,,但我常年bfs细节出错,,,re日常,,是时候总结一下了,,,
题解:裸的,但比赛时还是出错,,怎么就是会写错那些地方呢,,这次又是变量名写错了,,得总结学习一波命名艺术了看来,, 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
using namespace std;
int s, n, m;
bool visit[110][110];
struct pz
{
int ss, nn, mm, cs;
pz(int sss, int nnn, int mmm, int cc): ss(sss), nn(nnn), mm(mmm), cs(cc) {};
};
bool bfs()
{
queue<pz>q;
q.push(pz(s, 0, 0, 0));
visit[s][0] = false;
while(!q.empty()){
pz te = q.front();
q.pop();
if(te.ss == te.nn && te.ss + te.nn== s){
// printf("%d %d\n", te.ss, te.nn);
cout<< te.cs <<'\n';
return false;
}
/*能用循环优化这里,,但当时没有这么写,,也加入总结计划里面吧*/
int si = te.ss, ni = te.nn, mi = te.mm, ci = te.cs;
/****************s倒入n和m***********safe***/
if(si + ni >= n && visit[si - n + ni][n])q.push(pz(si - n + ni, n, mi, ci + 1)), visit[si - n + ni][n] = false;
else if(visit[0][ni + si])q.push(pz(0, ni + si, mi, ci + 1)), visit[0][ni + si] =false;
if(si + mi >= m && visit[si - m + mi][ni])q.push(pz(si - m + mi, ni, m, ci + 1)), visit[si - m + mi][ni] = false;
else if(visit[0][ni])q.push(pz(0, ni, mi + si, ci + 1)), visit[0][ni] =false;
/*****************n和m分别倒入s********safe*****/
if(si + ni >= s && visit[s][ni - s + si])q.push(pz(s, n - s + si, mi, ci + 1)), visit[s][ni - s + si] = false;
else if(visit[si + ni][0])q.push(pz(si + ni, 0, mi, ci + 1)), visit[si + ni][0] =false;
if(si + mi >= s && visit[s][ni])q.push(pz(s, ni, m - s + si, ci + 1)), visit[s][ni] = false;
else if(visit[si + mi][ni])q.push(pz(si + mi, ni, 0, ci + 1)), visit[si + mi][ni] =false;
/*****************n和m互倒************/
if(mi + ni >= m && visit[si][ni - m + mi])q.push(pz(si, ni - m + mi, m, ci + 1)), visit[si][ni - m + mi] = false;
else if(visit[si][0])q.push(pz(si, 0, mi + ni, ci + 1)), visit[si][0] =false;
if(ni + mi >= n && visit[si][n])q.push(pz(si, n, mi - n + ni, ci + 1)), visit[si][n] = false;
else if(visit[si][ni + mi])q.push(pz(si, ni + mi, 0, ci + 1)), visit[si][ni + mi] =false;
}
}
int main()
{
while(~scanf("%d%d%d", &s, &n, &m) && s != 0){
if(s % 2){
cout<<"NO\n";
continue;
}
memset(visit, 1, sizeof(visit));
int t;
if(n < m)t = m, m = n, n = t;
if(bfs())cout<< "NO\n";
}
return 0;
}
## F - 今夕何夕 HDU - 6112 | ||
题意:给T个日期,求最近哪一年里同一个日子和今天的星期数一样 |
||
题解:模拟,注意二月二十九日和闰年,我看了Albert_s的题解后了解到了蔡勒公式,就帖蔡勒公式版的代码吧 | ||
对了,当我把蔡勒公式单独拿出来计算时tle了,直接return就a了,具体原因再看下,我觉得应该是取模运算的原因
|
G - 第几天?
题意:中文题意, 比上一题模拟简单,,而且是同类型的,,自己跟不动榜后还是该看下其他题,万一有会的呢, 总结, 为什么这么菜呢??
题解:模拟,注意闰年
1 |
|
## H - 最大子矩阵 HDU - 1559 | ||
题意:中文题意,get到了新dp姿势,叫二维前缀和,画个图能很好很快理解 | ||
题解:新姿势的dp,存好每个点到最右下的那个点的和就好了 | ||
|
I - Help is needed for Dexter
题意:给一个数n,生成一个1到n的序列,每次选任意数减去一个数,最后整个序列全为0,且中途不能出现负数,求最小次数
题解:找规律类型
1~n|最小次数
1 1
1 2 | 同时减去1,得到1,同上,所以为2;
1 2 3 | 2,3同时减去2,得1,同1,所以为2;
1 2 3 4 | 3, 4同时减去2,得1 2 1 2,同二,所以为3;
很快,我们便能发现规律,当数位偶数时,能一步处理后一半,得到与前一半相同,也是与n/2相同的序列,能通过递归解决,当数为奇数时,能一步减去中间的数,得到前半部分+0+与前半部分相同的后半部分,等同于[n/2],所以可以利用递归解决
1 |
|
J - find your present (2)
题意:找到序列中出现一次的数
题解:做过相同的题,被强调过,异或解决
1 |
|
位运算的奇淫技巧
感觉又忘得差不多了呢