RC-u1 大家一起查作弊
在今年的睿抗比赛上,有同学的提交代码如下:
public asfiasfgwef12(){ int tsadflas=3; int masf11233=2; int[]wasdf1213= new int[10 +1]; int[] vasf124l = new int[10 + I]; int[][] ddasf1234p= new int[masf11233 ...
你肯定很奇怪,这看上去代码似乎不像是正常写出来的代码呀?没错,这是这位同学在网络上购买了所谓的“保研综测套餐”,商家为逃避赛后查重,给这位同学发去了经过混淆的代码。然而经过技术支持方的努力,这位同学不仅被封禁,与 TA 购买了相同“套餐”的同学也利用技术手段全部查出,目前主办方已向警方报案,这些同学的“保研”梦很有可能会转变为“案底”梦……因此如果你在比赛前也购买了类似的服务,现在迷途知返还来得及——毕竟这个商家起码还做了一些努力,许多商家号称“一对一”,实际上将一份代码发给了数十位同学……
回到题目,虽然具体检查的手段无法公开,但我们可以尝试简化再简化的手段来找到被这样混淆的程序。对于给定的大量字符串,你首先要提取出所有的关键词。一个关键词的定义是:由大写字母、小写字母、数字组成的字符串,并且前后均为非大小写字母及数字(包含开头及换行符)。如以下的字符串:
int[] vasf124l = new int[10 + I];
关键词为:
int
、vasf124l
、new
、int
、10
以及I
。然后对于所有关键词,你需要计算可疑分数的和以及关键词平均长度。其中一个关键词的可疑分数如下定义:
- 如果一个关键词同时包含大写字母、小写字母、数字,则分数 + 5 分;
- 否则,如同时包含(大写字母、数字)或(小写字母、数字)的,分数 + 3 分;
- 否则,如同时包含(大写字母、小写字母)的,分数 + 1 分;
- 其余情况不加分。
对于给定的数据,请你输出所有关键词的可疑分数的和、长度的和以及数量。
输入格式:
输入包含若干行字符串,表示待检测的程序。保证每行字符串的长度不超过 1000(除了一行最后的换行符外),输入总长度不超过 6×104,并且至少有一个关键词。
输出格式:
对于输入的所有字符串,第一行输出可疑分数的和,第二行输出关键词的总长度以及关键词的个数(以避免计算平均值带来的浮点误差),用一个空格隔开。
输入样例:
static void nnmMNBkf3kfa(){ int fefvB4=2; int [][]fsdk9A=new int[fefvB4][fefvB4]; fsdk9A[0][0]=1; for (int gfdgsUB3 = 0; gfdgsUB3 < fefvB4; gfdgsUB3++) { for (int fdnbXZ8 = 0; fdnbXZ8<fefvB4-gfdgsUB3-1; fdnbXZ8++) { fsdk9A[gfdgsUB3][fdnbXZ8+1]=fsdk9A[gfdgsUB3][fdnbXZ8]+gfdgsUB3+fdnbXZ8+2; fsdk9A[gfdgsUB3+1][fdnbXZ8]=fsdk9A[gfdgsUB3][fdnbXZ8]+gfdgsUB3+fdnbXZ8+1; break; } break; } }
输出样例:
155 276 54
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
题解:分割字符串,就是取他的关键词,然后给关键词赋分
#include "bits/stdc++.h" using namespace std; int aa(char c){//判断小写字母 if(c >= 'a' && c <= 'z' ) return 1; else return 0; } int bb(char c){//判断大写字母 if( c >= 'A' && c <= 'Z') return 1; else return 0; } int cc(char c){//判断数字 if(c >= '0' && c <= '9') return 1; else return 0; } int check(string s){//识别分数 int x = 0, y = 0, z = 0, zz = 0; for(int i = 0; i < s.length();i ++){ if(!x) x = aa(s[i]); if(!y) y = bb(s[i]); if(!z) z = cc(s[i]); } if(x + y + z == 3) return 5; else if((x + y) == 1 && z == 1) return 3; else if(x + y == 2) return 1; else return 0; } int main(){ string s; int ans = 0, ann = 0, l = 0; while(cin>>s){ string ss; int i = 0; while(i < s.length()){ //提取关键字 ss = ""; while(!(aa(s[i]) + bb(s[i]) + cc(s[i])) && i < s.length()) i ++;//去掉多余字符 while((aa(s[i]) + bb(s[i]) + cc(s[i])) && i < s.length()){ ss += s[i]; i ++; } if(ss != ""){ int xx = check(ss);//识别分数 ann ++; l += ss.length(); ans += xx; } } } cout<<ans<<endl<<l<<" "<<ann; return 0; }
RC-u2 谁进线下了?II
分数 20
全屏浏览
切换布局
作者 DAI, Longao
单位 杭州百腾教育科技有限公司
Xepa Legends 是一个第一人称射击类大逃杀(“吃鸡”)游戏,每局游戏共有 20 支 3 人小队参加,最后获胜的队伍被称为“捍卫者”。
最近 Xepa Legends 举行了亚太地区南赛区的线上比赛,争夺 7 个前往德国曼海姆参加线下赛的资格,国内共有 14 支队伍参与到了其中。因为比赛十分激烈,直到最后谁进了线下仍有巨大的疑问。小 K 喜欢的国内知名战队 DreamTear 因其队内选手杀马特表现不佳,正好卡在出线分数前后,请你赶紧帮帮小 K,计算一下最后的分数情况,看看他喜欢的战队出线了没有吧!
Xepa Legends 的常规赛共有 30 支队伍参加,被分为三组,进行 N 轮比赛,每轮由三组中的两组组成 20 支队伍的参赛阵容,进行若干场比赛,最后每个队伍会获得一个当轮比赛的排名。
对于每轮比赛,队伍会根据排名获得一个在当轮比赛的赋分:
排名 分数 第一名 25 分 第二名 21 分 第三名 18 分 第四名 16 分 第五名 15 分 第六名 14 分 第七名 13 分 第八名 12 分 第九名 11 分 第十名 10 分 第十一名 9 分 第十二名 8 分 第十三名 7 分 第十四名 6 分 第十五名 5 分 第十六名 4 分 第十七名 3 分 第十八名 2 分 第十九名 1 分 第二十名 0 分 给定若干轮比赛队伍获得的当轮比赛排名,请你计算出队伍的赋分,并在若干轮比赛后计算出总赋分,从而最终确定 DreamTear 战队能否进入线下,还是只能耍耍花招了。
例如,
- DreamTear 战队在第一轮比赛中获得了第 17 名,第三轮比赛中获得了第 11 名,第四轮比赛中获得了第 11 名,那么 DreamTear 战队可获 3 + 9 + 9 = 21 分的赋分;
- KV 战队在第一轮比赛中获得了第 10 名,第三轮比赛中获得了第 2 名,第四轮比赛中获得了第 6 名,那么他们可获得 10 + 21 + 14 = 45 分的赋分。
注:本题与实际情况无关,所有比赛规则、队伍、队员名称均为虚构。
输入格式:
输入第一行是一个正整数 N (≤20),表示有 N 轮比赛。
接下来有 N 部分输入,每部分是一轮比赛的情况。对每一场比赛,信息共分 20 行,第 i 行(i=1,⋯,20)给出的两个非负整数 c 和 p 表示编号为 c 的队伍在这轮比赛里获得了第 p 名。
数据保证所有给定的情况中,排名永远大于等于 1 且小于等于 20,队伍编号由 1 开始,不超过 30。
输出格式:
输出若干行,按分数从大到小依次输出队伍的编号及该队所有轮次游戏结束后的总分。如分数相同,队伍编号较小的先输出。
注意由于统计的时候比赛可能并没有完全结束,所以每个队伍参加的比赛轮数不一定相同,此时仍然正常计分统计即可。不要输出未参赛的队伍分数。
输入样例:
3 1 1 2 2 9 3 6 4 7 5 11 6 3 7 13 8 8 9 16 10 4 11 19 12 17 13 5 14 12 15 15 16 14 17 10 18 20 19 18 20 5 11 10 12 30 13 22 14 1 1 28 20 21 16 26 17 2 2 24 3 4 4 29 5 8 6 7 15 6 7 3 8 9 9 25 10 23 19 27 18 19 20 26 19 27 18 18 17 21 16 12 15 28 14 20 13 17 12 14 11 13 10 23 9 29 8 22 7 30 6 15 5 24 4 25 3 16 2 11 1
输出样例:
1 50 2 42 11 39 24 34 16 31 6 29 9 29 25 28 29 27 3 25 4 25 8 25 13 22 30 21 7 20 15 19 22 19 5 15 17 15 14 12 23 12 10 10 12 10 19 8 20 8 21 8 28 6 26 4 27 4 18 3
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
题解:这题直接模拟,就是注意一点就是没有参加比赛的不参与排名
#include "bits/stdc++.h" using namespace std; int r[30] = {0, 25, 21, 18, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; int a[40], flag[40]; struct node{ int id; int s; node(int x, int y) { id = x, s = y; } bool operator<(const node & b)const { if(s != b.s) return s > b.s; else return id < b.id; } }; vector<node> v; int main(){ int n, c, p; cin>>n; while(n--){ for(int i = 0; i < 20; i ++){ cin>>c>>p; flag[c] = 1; a[c] += r[p]; // node(c, p); } } for(int i = 1; i < 31; i ++){ if(flag[i] != 0) v.push_back(node(i, a[i])); } sort(v.begin(), v.end()); for(int i = 0; i < v.size(); i ++){ cout<<v[i].id<<" "<<v[i].s<<endl; } return 0; }
RC-u3 势均力敌
分数 25
全屏浏览
切换布局
作者 陈越
单位 浙江大学
用 n>2 个不同的个位数字组成一个 n 位数,显然有 n! 个不同的结果。可以证明,这 n! 个数字可以被分为势均力敌的两组 —— 即平方和相等、且个数也相等的两组。
本题就请你用程序验证一下这个结论。
因为本题是一道简单题,所以规模很小,只考虑 n≤4 的情况。输入格式:
输入第一行给出正整数 n(2<n≤4),随后一行给出 n 个不同的、在区间 [1, 9] 内的个位数字,其间以空格分隔。
输出格式:
将所有组成的 n! 个不同的 n 位数分为平方和相等、且个数也相等的两组。但你只需要输出其中一组就可以了。每个数字占一行,共输出 n!/2 行。
注意:解可能不唯一,输出任何一组解就可以。输入样例:
3 5 2 1
输出样例:
125 512 251
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
题解:其实就是两个过程,一个是寻找所有的排列组合,一个是寻找满足平方和相等的两个分块,这里其实可以用dfs,取一半的数,需要满足的条件是这些数的总和是所有数(这里的数指的是平方和)的和的一半就好了,不太理解我的意思的话可以直接看代码,我这里用的是没有返回值的dfs,有能力的(比如凳子学长)可以用有返回值的,哈哈,我老是会搞晕这些,所以干脆就不要返回值了
#include "bits/stdc++.h" using namespace std; vector<int> v,vv, w, ww; int a[6]; int n; long long ans = 0; int flag = 0; void dfs(int i, long long res){ if(i > v.size() ) return; if(w.size() == v.size() / 2){ if(res == ans / 2){ ww = w; return; } } else{ w.push_back(v[i]); dfs(i + 1, res + vv[i]); w.pop_back(); dfs(i + 1, res); } } int main(){ cin>>n; for(int i = 0; i < n; i ++){ cin>>a[i]; } sort(a, a + n); do{ int x = 0; for(int i = 0; i < n; i ++){ x = x * 10 + a[i]; } v.push_back(x); vv.push_back(x * x); ans += x * x; }while(next_permutation(a, a + n)); dfs(0, 0); for(int i = 0; i < ww.size();i ++){ cout<<ww[i]<<endl; } return 0; }
RC-u4 City 不 City
分数 30
全屏浏览
切换布局
作者 陈越
单位 浙江大学
“City 不 City”因为一位外国友人保保熊直播旅游时总是用奇怪的腔调说“好 city,啊!”而走红中国社交网络,成为网络热梗。事实上,有一些叛逆的年轻人在旅行时会刻意避开网红打卡点,选择一些小众的特色地方小城镇,不追求 city,而喜欢说“好 country,啊”。
下面给定各个城镇的旅游热度和城镇间的旅行花销,请你为前来咨询的旅行者规划一条最经济的路线,并且尽可能避开热度很高的网红点。输入格式:
输入第一行首先给出 4 个正整数:n 和 m(1<n≤103,1≤m≤5n),依次为城镇数量(于是城镇编号从 1 到 n)和城镇间的通路条数;s 和 t 依次为旅行者的出发地和目的地的城镇编号。
随后一行给出 n 个不超过 100 的正整数,依次为 n 个城镇的旅游热度。
再后面是 m 行,每行给出一条通路连接的两个城镇的编号、这条通路的最小花销(其数值为不超过 103 的正整数)。通路是双向的,题目保证任一对城镇间至多给出一条通路。
同一行的数字间均以空格分隔。输出格式:
题目要求从 s 到 t 的最小花销路线;若这样的路线不唯一,则取途径城镇的最高旅游热度值最小的那条路线。
在一行中输出从 s 到 t 的最小花销、以及途经城镇的最高旅游热度值(若没有途经的城镇,则热度值为 0)。数值间以 1 个空格分隔,行首尾不得有多余空格。
若从 s 根本走不到 t,则在一行中输出Impossible
。输入样例 1:
8 14 7 8 100 20 30 10 50 80 100 100 7 1 1 7 2 2 7 3 1 7 4 2 1 2 1 1 5 2 2 5 1 3 4 1 3 5 3 3 6 2 4 6 1 5 6 1 5 8 1 6 8 2
输出样例 1:
4 50
样例解释:
从 7 到 8 的最短路径有 3 条,其中 2 条都经过城镇 1,于是对应的最高旅游热度值是城镇 1 的热度值 100。解路径为 7->2->5->8,途径城镇 2 和 5,对应的最高旅游热度值是城镇 5 的热度值 50。在最短路径长度相等的情况下,取热度值小的解,故输出的热度值为 50。
输入样例 2:
3 1 1 2 10 20 30 1 3 1
输出样例 2:
Impossible
代码长度限制
16 KB
Java (javac)
时间限制
800 ms
内存限制
512 MB
其他编译器
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
题解:说起来挺好笑的,我这个是在赛场上满分过的,过了二十天我补题的时候突然发现wa了几个点,还是翻的当时的代码才想起来的,其实就是一个最短路,但是注意维护的是一条路上的最高的热度的最小,所以要找所有的最短路的里面最高的热度的最小值,这里我是用了一个数组保存,类似于dis数组的思想吧(ps:我发现我写的最短路和csdn很多博主的都不一样,老师一开始就是这么教的,我觉得还挺好用的哈哈)
#include "bits/stdc++.h" using namespace std; const int N = 1000 + 10; typedef long long ll; int a[N]; ll dis[N]; int tem[N]; int ans = 200; struct edge{ int id; ll dis; edge(int a, ll b){ id = a, dis = b; } }; struct point{ int n_id; ll n_dis; int tem; point(int a, ll b, int c){ n_id = a, n_dis = b, tem = c; } bool operator < (const point & b) const{ if(n_dis != b.n_dis) return n_dis > b.n_dis; else return tem > b.tem; } }; bool done[N]; vector<edge> g[N]; int tt, n; void d(int s){ priority_queue<point> q; for(int i = 1; i <= n; i ++){ dis[i] = N * 100; tem[i] = a[i]; } dis[s] = 0; q.push(point(s, dis[s], a[s])); while(q.size()){ point t = q.top(); q.pop(); if(t.n_id == tt) if(ans > t.tem) ans = t.tem; if(done[t.n_id] ) continue; done[t.n_id] = true; int x = t.n_id; ll diss1 = t.n_dis; int tem1 = t.tem; // cout<<x<<endl; for(int i = 0; i < g[x].size(); i ++){ int xx = g[x][i].id; if(done[xx]) continue; ll diss2 = g[x][i].dis; if(dis[xx] > diss1 + diss2 || dis[xx] == diss1 + diss2 && tem[xx] > max(tem[x], a[xx]) ) { dis[xx] = diss1 + diss2; tem[xx] = max(tem[x], a[xx]); q.push(point(xx, dis[xx], tem[xx])); } } } } int main(){ int m, s, aa, b, c; cin>>n>>m>>s>>tt; for(int i = 1; i <= n; i ++) cin>>a[i]; a[s] = 0, a[tt] = 0; for(int i = 0; i < m; i ++){ cin>>aa>>b>>c; g[aa].push_back(edge(b, c)); g[b].push_back(edge(aa, c)); } d(s); if(dis[tt] == N * 100) cout<<"Impossible"; else { cout<<dis[tt]<<" "<<ans; } return 0; }
RC-u5 贪心消消乐
分数 30
全屏浏览
切换布局
作者 陈越
单位 浙江大学
“消消乐”是以消去方块赢取分数的游戏。这里介绍一种超级简单的玩法:玩家每次按住并拖动鼠标,在屏幕上划出一个矩形,则矩形内的方块就被消去,玩家得到所有被消去的方块的分数之和。
每个方块上的小动物对应不同的得分,例如消去上图中的绿色青蛙得 2 分、消去紫色猫头鹰得 5 分、消去黄色小鸡得 9 分、消去蓝色小牛得 1 分、消去红色狐狸得 3 分、消去棕色小熊得 8 分。有些方块是冰块,消去冰块会被扣分,所以冰块上标注了负分。有些方块是黑洞,玩家的矩形内不能包含任何黑洞,否则所有分数都被黑洞吸走。在一个矩形被消去后,其上方的方块会掉落以填补空缺,而多出的空缺被黑洞填补。
本题请你帮助玩家实现一个基于贪心策略的自动消除程序,每次都争取获得最多的分数,直到无法继续获得更多的分数。输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出一个不超过 100 的正整数 N,对应正方形游戏屏幕的高度和宽度。随后 N 行,每行给出 N 个数字,代表对应方块的分数,其中黑洞用 0 表示,小动物用正整数分表示,冰块用负整数分表示。数值均在 [−100,100] 区间内。
输出格式:
每一步的消除策略占一行,格式为:
(x1, y1) (x2, y2) 得分
其中
(x1, y1)
为矩形左上角的横纵坐标,(x2, y2)
为矩形右下角的横纵坐标,得分
为消去这个矩形的得分。这里我们将游戏屏幕的左上角坐标定义为 (1,1),右下角坐标定义为 (N,N)。
最后一行给出总分。
注意:当有多个矩形同时对应最大得分时,优先选择x1
最小的;如果x1
一样,则优先选择y1
最小的;如果y1
也一样,则优先选择x2
最小的;如果x2
还是一样,则优先选择y2
最小的。输入样例:
4 0 2 5 0 9 2 -6 2 -4 1 -4 3 -1 8 0 -2
输出样例:
(1, 2) (2, 4) 15 (3, 1) (3, 1) 5 (4, 2) (4, 3) 5 (2, 4) (2, 4) 2 27
样例解释:
游戏的初始界面如题面所示。消去过程如下:
代码长度限制
16 KB
Java (javac)
时间限制
2000 ms
内存限制
512 MB
Python (python3)
时间限制
2000 ms
内存限制
256 MB
其他编译器
时间限制
2000 ms
内存限制
64 MB
栈限制
8192 KB
题解:这个题呢,我在赛场上甚至都没开始看哈哈哈,(其实我当时都有点开心了,没想到我能拿第四题的满分,属实有点小开心了,虽然依然很菜,争取吧,争取下次国一哈哈哈)这个题是今天看的大佬的题解 2024 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)-CSDN博客
这里附上链接,感谢大佬让我了解了二维前缀和哈哈
#include "bits/stdc++.h" using namespace std; const int N = 1001; int n; int a[N][N], b[N][N], c[N][N]; void init_a(int x1, int y1, int x2, int y2){ for(int i = x1; i <= x2; i ++){ for(int j = y2; j >= 1; j --){ int len = y2 - y1 + 1; if(j - len < 1) a[i][j] = 0; else { a[i][j] = a[i][j - len]; } } } } void init_b(){//进行二维前缀和的数据建立 for(int i = 1; i <= n; i ++){ for(int j = 1; j <= n; j ++){ b[i][j] = b[i - 1][j] + b[i][j - 1] + a[i][j] - b[i - 1][j - 1]; } } } void init_c(){ for(int i = 1; i <= n; i ++){ for(int j = 1; j <= n; j ++){ int x = 0; if(a[i][j] == 0) x = 1; else x = 0; c[i][j] = c[i - 1][j] + c[i][j - 1] + x - c[i - 1][j - 1]; } } } int ask_b(int x1, int y1, int x2, int y2){//查看每一块的分数 return b[x2][y2] - b[x1 - 1][y2] - b[x2][y1 - 1] + b[x1 - 1][y1 - 1]; } int ask_c(int x1, int y1, int x2, int y2){//这个是查看每一块有没有黑洞 return c[x2][y2] - c[x1 - 1][y2] - c[x2][y1 - 1] + c[x1 - 1][y1 - 1]; } int main(){ // int n; cin>>n; for(int i = 1; i <= n; i ++) for(int j = 1; j <= n; j ++) cin>>a[j][i]; init_b(), init_c(); // int ans = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; int ans1 = 0; while(1){ int ans = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; for(int i = 1; i <= n; i ++){ for(int j = 1; j <= n; j ++){ for(int l = i; l <= n; l ++){ for(int r = j; r <= n; r ++){ if(ask_c(i, j, l, r)) break;//有黑洞就清零了,所以ans就直接是0了,在我们循环的初始化就是ans为零,所以就可以直接跳过 else { int res = ask_b(i, j, l, r); if(res > ans){//贪心选择最大的分数 ans = res; x1 = i, y1 = j, x2 = l, y2 = r; } } } } } } if(ans == 0) break; else if(ans > 0) printf("(%d, %d) (%d, %d) %d\n",x1, y1, x2, y2, ans); ans1 += ans; init_a(x1, y1, x2, y2);//模拟掉落 init_b(), init_c(); } cout<<ans1; return 0; }
最后总结一下:我感觉这次能拿国二主要还是题目比较简单,然后之前正好练的最短路比较多,当时一看到第四题直接就上手了,这次的经验告诉我,一定多刷题,刷着刷着手感就来了,今天补题的经历告诉我,做过的题目还是要经常回顾,常见常新嘛,让手感变成自己的东西靠的就是理解和深入,多多领略,在非刷题状态下也能熟练解决问题这样才不是做死题,死刷题,只靠肌肉记忆是不长久的,脑记忆才是根基。还有就是最近蒋老师在督促我们准备重庆赛了,真的真的超级想赢一次,真的就赢一次!还有两个月,这两个月我估计会练的比较勤,小牛老师那边的课题我想着稍微放一放,因为这个女生赛是我们一直一直想去争取的东西!加油吧少年!!!