avatar
fireworks99
keep hungry keep foolish

浪潮杯第十届山东省大学生ACM程序设计竞赛

ZOJ题目总链接(4113~4125)

A.Calander

给出一个新的日期计算方法,一周五天(周一至周五),一月6个周(30天),一年有这样的十二个月,给出一个日期及其星期,另给出一个日期,求出星期

总结

一看日期计算 —> 形成思维定式:不就是求两个日期差 % 5吗!

后来各种错:

  1. % 5 之后对应数字为0~4,要搞清楚其对应周几
  2. 封榜后发现与年份无关,一年是那固定的360天,% 5 == 0
  3. 赛后再想想与月份都无关,一个月是那固定的30天, % 5 == 0

所以,题目给出一个新事物(或是旧事物的变式),一定要先找其运行规律,总结特点,抓住特点去做,不要因着急而盲目去做。一个人在敲这个题时,另外两人不仅要思考这方法是否正确、细节是否都注意到了、特判做到了,还要想想是否有更简单的方法,因为更简单的方法一定是更优的,是更能体现参赛者水平的,是出题人想看到的。

Code

#include <map> #include <cstdio> #include <iostream> using namespace std; int main() { int t; scanf("%d", &t); map<int, string> mp; mp[1] = "Monday"; mp[2] = "Tuesday"; mp[3] = "Wednesday"; mp[4] = "Thursday"; mp[5] = "Friday"; while(t--) { int ay, am, ad, by, bm, bd, idx; string s; scanf("%d%d%d", &ay, &am, &ad); cin >> s; switch(s[1]) { case 'o': idx = 1; break; case 'u': idx = 2; break; case 'e': idx = 3; break; case 'h': idx = 4; break; case 'r': idx = 5; } scanf("%d%d%d", &by, &bm, &bd); int tem = 30 - ad + bd; tem %= 5; if((idx + tem) % 5 == 0) cout << "Friday" << '\n'; else cout << mp[(idx + tem) % 5] << '\n'; } return 0; }
  • 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

B.Flipping Game

updating……

C.Wandering Robot

一个机器人按照一个长度为n的指令串重复走k次,求其离原点的最远“折线距离”

总结

第一次我想出一个思路:

执行一次指令串后离原点的距离 * (k - 1) + 最后一次的最优解:WA

研究了一会儿,队友发现:最后一次的最优解可能并不是前(k-1)次位移方向上的!

过了53分钟修改上交:WA

耽误时间长了去看了D题,没敲对,C题int改longlong交了一遍?WA

队友提出利用坐标,发现这种思路跟之前的一样,不过实现起来思路更清晰:WA

队友提出遗漏:答案也可能只是第一次的最优解(比如只执行两次指令时):AC

  1. 在纸上多画图、多模拟,不至于看不出来第一个错误!

  2. 多思考队友的思路、提出的建议,不要第一时间想着反驳

    (当这题的第一个思路(或主思路)是自己想出来的时候,心里有种不愿别人提出异议的感觉?一种不容别人提出更完善策略的感觉?你的思路跟我的一样,只不过实现方式不一样,我的理应就是对的,即使错了,那你的思路跟我一样必然也是错的)可是你不想想,同一思路换种实现方法可能更清晰呢!

  3. 多质疑自己,将错误的险隘思路拓宽

Code

#include <cmath> #include <string> #include <cstdio> #include <iostream> using namespace std; int len; string s; long long x, y; long long cal() { long long ans = 0; for(int i = 0; i < len; ++i) { if(s[i] == 'U') y++; if(s[i] == 'D') y--; if(s[i] == 'L') x--; if(s[i] == 'R') x++; if(ans < abs(x) + abs(y)) ans = abs(x) + abs(y); } return ans; } int main() { int t; scanf("%d", &t); while(t--) { int n, k; scanf("%d%d", &n, &k); cin >> s; len = s.length(); x = 0, y = 0; long long first = cal(); x *= (k - 1); y *= (k - 1); long long tem = cal(); cout << max(first, tem) << '\n'; } return 0; }
  • 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

D.Game on a Graph

k个分属两阵营的人在一地图上玩游戏,n个点,m条边,每人轮流拿一条边,最后谁拿走便后图不连通了,那个人所在阵营就lose,对面win

总结

信誓旦旦地跟队友说是水题(不过确实是),这题k可以不给出(s.length()自己算),后面m组输入完全用不到。

k个人玩,n个点,只需n-1条边

m条现有边,可以拿走(m - (n - 1)) == m - n + 1条

则下一个人(m - n + 2)所属阵营lose

不过我急于交题去看C,疏忽了,没有%,罚时了

Code

#include <cstdio> #include <string> #include <iostream> using namespace std; int main() { int t; scanf("%d", &t); while(t--) { int k, a, b; scanf("%d", &k); string s; cin >> s; int n, m; scanf("%d%d", &n, &m); for(int i = 0; i < m; ++i) scanf("%d%d", &a, &b); int tem = (m - n + 2) % k; if(tem == 0) tem = k; if(s[tem - 1] == '1') cout << '2' << '\n'; else cout << '1' << '\n'; } return 0; }
  • 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

E.

updating……

F.Stones in the Bucket

水题(没有坑)

code

#include <cstdio> #include <iostream> using namespace std; int a[100005]; int main() { int t; scanf("%d", &t); while(t--) { int n; long long sum = 0; long long ans = 0; scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%d", &a[i]); sum += a[i]; } ans += sum % n; int tem = sum / n; for(int i = 0; i < n; ++i) if(a[i] < tem) ans += (tem - a[i]); cout << ans << '\n'; } return 0; }
  • 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

G.

updating……

H.Tokens on the Segments

这种题应该是经常出现,求最优分配

暴力贪心:

按左界从小到大排序,左界相同按右界从小到大排序

线段从最右向左遍历,每个点也从右向左遍历,相当于“采用了”满足条件的最右点(也是接下来最可能用不到的点)

#include <map> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int N = 100005; struct node { int l, r; } a[N]; bool cmp(node a, node b) { if(a.l != b.l) return a.l < b.l; else return a.r < b.r; } int main() { int t; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); for(int i = 0; i < n; ++i) scanf("%d%d", &a[i].l, &a[i].r); sort(a, a + n, cmp); map<int, bool> mp; int ans = 0; for(int i = n - 1; i >= 0; --i) for(int j = a[i].r; j >= a[i].l; --j) if(!mp[j]) { mp[j] = 1; ans++; break; } cout << ans << '\n'; } return 0; }
  • 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

I.

updating……

J.

updating……

k.

updating……

L.Median

n个点,m个关系(a > b),求是否可以知道哪些数字可以作为中位数

总结

开场我就看了这题,说好了我从后往前看,结果漏看了M题?!以为有封面吗?!

一眼看去像拓扑排序,但…但是什么呢,忘了当时哪里不明白了,不过后来发现这题可能的中位数不止一个,当时没认识到这一问题

虑中位数的特殊性,中位数意味着一定有n个比它大的,n个比它小的,所以对于1<= x <= n,在给出的关系里寻找比它大数字的个数(入度)的和比它小的数字的个数(出度),只要两者都<= 2/n,就说明可以是中位数

不过最遗憾的是:我明明做过floyd闭包传递(传递闭包的含义指通过传递性推导出尽量多的元素之间的关系https://fireworks99.github.io/2019/04/07/POJ-3660-Cow-Contest/ 在场上却什么也想不出来,还是做少了…

Code of floyd

#include <cstdio> #include <bitset> #include <cstring> #include <iostream> using namespace std; int n, m; bool r[105][105]; int out[105]; int in[105]; void floyd() { for(int k = 1; k <= n; ++k) for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) if(r[i][k] && r[k][j]) r[i][j] = 1; } int main() { int t; scanf("%d", &t); while(t--) { memset(r, 0, sizeof(r)); memset(out, 0, sizeof(out)); memset(in, 0, sizeof(in)); scanf("%d%d", &n, &m); int a, b; for(int i = 0; i < m; ++i) { scanf("%d%d", &a, &b); r[a][b] = 1; } floyd(); bool flag = 1; for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) { if(r[i][j] && r[j][i])///r[1][1] == r[1][1] == 1 { flag = 0; break; } if(r[i][j]) { out[i]++; in[j]++; } } if(!flag) for(int i = 0; i < n; ++i) cout << '0'; else { for(int i = 1; i <= n; ++i) if(in[i] <= (n >> 1) && out[i] <= (n >> 1)) cout << '1'; else cout << '0'; } cout << '\n'; } return 0; }
  • 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

improved Floyd

#include <bitset> bitset<105> r[105]; void floyd() { for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) if(r[j][i]) r[j] |= r[i]; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

M.Sekiro

水题,坑:n == 0 n == 1 && k == 1e9

Code

#include <cstdio> #include <iostream> using namespace std; int main() { int t; scanf("%d", &t); while(t--) { int n, k; scanf("%d%d", &n, &k); while(k--) { n = (n + 1) >> 1; if(n == 1 || n == 0) break; } cout << n << '\n'; } return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy