比赛链接:https://ac.nowcoder.com/acm/contest/43898
作为大二的同学,第一次参加江西省赛,运气还不错,最后做出三题获得了二等奖,感谢我的队友在赛时的一起努力,还有志愿者为我们的无私奉献,特别感谢C老师为我们的操劳,周日一早就来机房为我们做准备,还有准备的午饭非常好吃,竟然有四个菜(我平时都没这么丰盛!!! 可惜的是这次的举办方为江西省教育厅,不是ICPC组委会,不然就是银牌爷了哈哈。
L Thunder God ’s Hammer 签到。 开赛时一刷新网页,竟然有人几秒钟就过题,于是我直接打开L,题都没看完就开始#include <iostream>,2min就过了哈哈,交完发现28名,实在是手速题。
最后省赛榜单公布,如果三分钟之内过了L,竟然可以拿一个三等奖(难道是因为江西省太菜了x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <iostream> using namespace std;int n;int main () { cin >> n; for (int i = 1 ; i <= n; i++) { int a, b, c, d; cin >> a >> b >> c >> d; cout << a * b * c * d << endl; } return 0 ; }
A Special Adjustment Method 题意:给三个非负数x,y,z,可以做n次操作(n可以等于0),每次操作k可以使一个数+2,两个数-1(操作过程中数要非负),求$x^2+y^2+z^2$的最大值。
WA了六发的神题,导致我们罚时爆炸,我们一开始发现要让小的数尽量小,大的数尽量大,然后直接排序后把最小的数减小为0,最大的数增加很多个2,交了一发WA。 然后X和Y同学灵机一动,发现最小的数如果先加大一点,加大到和中间的数差不多大,再一起减小,这样最大的数会更大,于是写了一发模拟,又WA。 然后X同学又发现,只要两个小的数相差是三的倍数,那么就可以一起减到0,如果不是就会减成01,写了一发又WA,百思不得其解。
于是我们换题写B。。。 B写不出来,又换回A。
通过智慧样例,我们把条件改成if (a[1] == a[2] || ((a[1] - a[0]) % 3 == 0)),结果又WA! 最后我发现可以if (((a[2] - a[1]) % 3 == 0) || ((a[1] - a[0]) % 3 == 0)),然后后WA,最后我乱打了一个测试样例1 9 10发现如果最小的和最大的相差3的倍数,也可以达成0 0的结果,提交了一发终于AC!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <algorithm> #include <cstring> #include <iostream> using namespace std;int main () { int t; cin >> t; for (int i = 1 ; i <= t; i++) { long long a[3 ]; cin >> a[0 ] >> a[1 ] >> a[2 ]; sort (a, a + 3 ); if (((a[2 ] - a[0 ]) % 3 == 0 ) || ((a[2 ] - a[1 ]) % 3 == 0 ) || ((a[1 ] - a[0 ]) % 3 == 0 )) cout << (a[0 ] + a[1 ] + a[2 ]) * (a[0 ] + a[1 ] + a[2 ]) << endl; else cout << (a[0 ] + a[1 ] + a[2 ] - 1 ) * (a[0 ] + a[1 ] + a[2 ] - 1 ) + 1 << endl; } return 0 ; }
B 01string 题意:给一个序列s0由0和1组成。s1比s0少最后一位,并且其中第i位上的值为s0上的max(i,i+1),以此类推s2,s3…。给序列s0和数字k,求s0,s1,s2….sk的所有序列中1的总个数。
很奇怪的题目,我的队友写了两个小时等差数列还没过,他们给我解释我也听不懂,于是我去吃中饭。我还以为这个思路有问题,没想到最后题解出来,和他们的思路适合是相匹配的,但是我还是看不懂呜呜。
说说我的AC思路,对于序列中的每一个字母,我们用ap(appeareance)来表示它第一次出现1的时间,如果在是s0时就是1了,那我就就记录为0,如果在s1的时候出现1,那就记录为1。再用dis(disappear)来记录这个数字消失的时间,因为从s0-s1会丢失最后一个字母,s1-s2又会丢失最后一个字母,如果这个数字是在s1的时候消失的(它是最后一个字母),我们就记录为0。
对于每一个序列的字母,要求他们的ap,我们只需要记录它距离它右边最近的一个1的距离即可(因为它只能被右边的1更新)。要求他们的dis,我们只需要记录它离字符串末尾的距离即可。
求出每个序列的ap和dis,要求k时1的总数,就只需要遍历一遍序列,如果出现(ap)在k之前,那就加上dis-ap,如果k在ap后,那就不用管,这样只需要遍历一遍序列就可以求解出答案了。
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 #include <algorithm> #include <cstring> #include <iostream> #define int long long using namespace std;signed main () { ios::sync_with_stdio (0 ), cin.tie (0 ); int t; cin >> t; for (int i = 0 ; i < t; i++) { int n, k; cin >> n >> k; string a; cin >> a; int last1 = 0x3f3f3f3f ; int ap, dis; int cnt = 0 ; for (int j = n - 1 ; j >= 0 ; j--) { if (a[j] == '0' ) ap = last1 - j; else last1 = j, ap = 0 ; dis = n - j; if (ap < k) { if (dis > k) cnt += k - ap + 1 ; else cnt += dis - ap; } if (ap == k) cnt++; } cout << cnt << endl; } return 0 ; }
C Graphic Game 给一个 2×𝑛 个点,𝑚 条边,没有重边和自环的无向图,每次可以选择两个度数相等的点删除,求删完所有点的方案
赛时是手写了一个find函数,用来找两个最大的点,
度数的可能取值有 1,…,𝑚,而点数 2×𝑛>𝑚 个,即一个无向图最少存在两个点的度数相等,删除两个点后仍然是一个无向图,即该问题一定有解,先存下每个度数对应的节点,考虑从最大的度数开始删除两个数,用 𝑠𝑒𝑡 维护即可,为什么这样一定能删完?即现在要证明不存在这样一种情况:删除当前度数为 𝑡 的两个数后,所有度数 𝑥<=𝑡 的节点个数都不超过 1,但是可能存在度数 𝑥>𝑡 的节点个数超过 1,可以发现这样的情况很难构造出来,因为对于一个度数 𝑥>𝑡 的节点来说,说明会有 𝑥 条边由该节点连向其他节点,假设如果其他点的度数都 ≤𝑡,而有 𝑥 个这样的点,说明至少存在两个度数相等的点,假设不成立,故与该节点连的点中至少存在一个点的度数 >𝑡,即我们的那种要证明的不存在的情况说明:度数大的点至少也会跟度数大的点连边,且所有其他度数小的节点都不存在相等度数的节点,这样的情况更加难以构造。 source:https://www.cnblogs.com/zyyun/p/16819062.html
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #include <bits/stdc++.h> using namespace std;template <typename T>void inline read (T &x) { int f = 1 ; x = 0 ; char s = getchar (); while (s < '0' || s > '9' ) { if (s == '-' ) f = -1 ; s = getchar (); } while (s <= '9' && s >= '0' ) x = x * 10 + (s ^ 48 ), s = getchar (); x *= f; } const int N = 2e6 + 10 , M = 1e6 + 10 ;int h[N], e[N], ne[N], idx;int n, m;int d[N];set<int > deg[M]; void add (int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }int main () { read (n), read (m); memset (h, -1 , sizeof h); for (int i = 1 ; i <= m; i++) { int a, b; read (a), read (b); add (a, b), add (b, a); d[a]++, d[b]++; } for (int i = 1 ; i <= 2 * n; i++) deg[d[i]].insert (i); int t = m; while (t >= 0 ) { if (deg[t].size () >= 2 ) { int x = *deg[t].begin (); deg[t].erase (deg[t].begin ()); int y = *deg[t].begin (); deg[t].erase (deg[t].begin ()); printf ("%d %d\n" , x, y); d[x] = d[y] = 0 ; for (int i = h[x]; ~i; i = ne[i]) { int j = e[i]; if (d[j] > 0 ) { deg[d[j]].erase (j); d[j]--; deg[d[j]].insert (j); } } for (int i = h[y]; ~i; i = ne[i]) { int j = e[i]; if (d[j] > 0 ) { deg[d[j]].erase (j); d[j]--; deg[d[j]].insert (j); } } } else { t--; } } return 0 ; }