2018-ICPC-焦作现场赛(复现)(A,D,E,F,I 题)题解

it2026-08-17  7

稍稍总结一下:铜牌题目难度较低,5题都不涉及数据结构,基本算是思维题。手速快罚时少的话甚至能拿银。复现赛三小时出了5题,应该是当时现场赛的银尾排名了。

A.Xu Xiake in Henan Province

签到题,有手就行

#include <bits/stdc++.h> using namespace std; string res[] = {"Typically Otaku","Eye-opener","Young Traveller","Excellent Traveller","Contemporary Xu Xiake"}; signed main(){ int t; cin>>t; while(t--){ int cnt = 0; for(int i = 0 ; i < 4 ; i ++){ int x; cin>>x; cnt += (x > 0); } cout<<res[cnt]<<endl; } }

D. Keiichi Tsuchiya the Drift King

给出a,b,d,r,求w。 要求小车的b边始终要贴在圆弧上且保持相切。

思路:简单计算几何

对于给定的角度d,如果d>=x,如下图。那么直接从左上角连一条线到圆心。这个长度就是路的最大宽度+r。显然很好求。 如果d < x 呢。w显然是比上一个结论要小的。如下图: 可以发现宽度显然小于w,因为左边还有挺大的空隙。那么红线(2)依然很容易求出来的,然而答案不是红线,而应该是黄色的线。所以用公式把黄色线求出来然后 - r 就是答案了。

AC代码:
#include <bits/stdc++.h> using namespace std; signed main(){ int t; cin>>t; while(t--){ double a,b,r,d; cin>>a>>b>>r>>d; d = d/180*acos(-1); // 转化为弧度 double red = sqrt((a+r)*(a+r)+b*b); double x = acos((a+r)/red); if(x <= d){ printf("%.12f\n",red-r); }else{ double y = x-d; double yellow = red*cos(y); printf("%.12f\n",yellow-r); } } }

E. Resistors in Parallel

给了一个并联电阻的阻值计算公式。以及两个限制条件。

对于一个有平方因子的数。他的阻值接近于无穷大。

思路:

总共有1-n,n种选择,每种选择就是这个数的所有约数的倒数的倒数。显然要使得R最小,也就是需要让下面的分子和越大。要让下面的和最大,就是要让项数尽量多,并且,每一项都尽量大,也就是分母尽量小,也就是一个数的约数尽量多,且每个约数尽量小。 仔细想想题目的限制条件,若一个数有平方因子,那么其实平方因子对答案的贡献为0,因为阻值无穷大,倒数就是趋于0。比如 12,有因子,1,2,3,4,6,12,其中 4 和 12 的贡献都为0, 所以12的贡献也就等价于6的贡献。 进一步总结就是找到一个数 x,x <= n,并且 x = 21315171…… 也就是x 是前k个质因子的乘积。 因为这样的数一定是因子数尽量多且每个因子尽量小的数。简单证明就是任意替换一个指数为0,最后的答案是比指数为1的小的。 那问题就简单了,第一步把质因子打表出来,可以发现乘到541的时候就超过 100位数 了。后面的没必要再算。 然后就是计算所有的约数和。 根据公式,下面的分母就是 x,分子就是x的所有约数的和。 利用公式:sum = (20+21+22…)*(30+31+32…)*(50+51+52…) 然后求gcd取最简分数形式就行了 当然 数据范围 巨大。要不用大数板子,要不用java/python,复现赛能交python就写python了

AC代码:
t = int(input()) li = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541] def gcd(x,y): if(y == 0): return x else: return gcd(y,x%y) for i in range(t): n = int(input()) res = 0 sum1 = 1 for i in li: if(sum1*i > n): break res += 1 sum1 *= i res1 = 1 for i in range(res): res1 *= (li[i]+1) # print(res1) g = gcd(sum1,res1) print(str(sum1//g)+"/"+str(res1//g))

F. Honeycomb

给一个这样的迷宫,求 起点S - 终点T 最少要经过几个六角形。

样例输入

1 3 4 +---+ +---+ / \ / \ + +---+ +---+ \ \ / \ + + S +---+ T + / \ / / + +---+ + + \ \ / \ +---+ +---+ + / / + +---+ + + \ / \ +---+ +---+ + \ / \ / +---+ +---+

样例输出

7
思路:

显然是一个bfs模板题啊。但是这个迷宫不是简单的二维数组。一开始的想法是,把迷宫压平变成一个二维数组表示的迷宫。但是越想越复杂。后来想直接存字符表示的迷宫就好了啊,而且4050*8050的字符数组也不会爆内存。 然后就是直接码代码了。

AC代码:
#include <bits/stdc++.h> //#define int long long using namespace std; char mp[4050][8050]; bool vis[4050][8050]; struct node{ int x,y,step; node(){} node(int _x,int _y,int _step){ x = _x; y = _y; step = _step; } }; int dir[][2] = {-2,-6,-2,6,2,-6,2,6,-4,0,4,0}; int dir2[][2] = {-1,-3,-1,3,1,-3,1,3,-2,0,2,0}; queue<node> que; int sx,sy,tx,ty; // start end point int bfs(){ while(!que.empty()) que.pop(); que.push(node(sx,sy,1)); vis[sx][sy] = 1; while(!que.empty()){ node now = que.front(); que.pop(); if(now.x == tx && now.y == ty) return now.step; for(int i = 0 ; i < 6 ; i ++){ int xx = now.x + dir[i][0]; int yy = now.y + dir[i][1]; int x1 = now.x + dir2[i][0]; int y1 = now.y + dir2[i][1]; // cout<<x1<<" "<<y1<<" "<<mp[x1][y1]<<endl; if(mp[x1][y1] == ' ' && !vis[xx][yy]){ vis[xx][yy] = 1; que.push(node(xx,yy,now.step+1)); } } } return -1; } signed main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m);getchar(); for(int i = 0 ; i < 4*n+3 ; i ++){ int pos = 0; char ch; while((ch = getchar()) && ch != '\n'){ if(ch == 'S') sx = i,sy = pos; if(ch == 'T') tx = i,ty = pos; vis[i][pos] = 0; mp[i][pos++] = ch; } } cout<<bfs()<<endl; } }

I. Distance

给定一条直线上n个点的位置。求 选出1-n个点时 。所有点对的距离和的最大值。

思路:贪心。

选一个点时为0,显然成立。 选两个点时,选最左端和最右端的,显然成立。 选三个点时,选最左端和最右端的,加中间任意一个。因为中间任意一个到这两个点的距离和都等于这两个点本身的距离。 选四个点时,最左端和最右端的点肯定是要选的。假设左右端点的距离为x1那么加入一个点时,距离和增加x1 再加入一个点时仍然要增加x1。且再增加新增的两个点的距离x2。那么显然之前选x1时就已经是最优解,再往后选这两个点都是固定的不会动。那么只能让x2尽量大。也就是选择目前最靠左和最靠右的两个点。 推广结论。 当前选择的点如果是第奇数个,之前说明已经选择了偶数个点。这个点可以任意选,并且加入这个点时,增加的距离就是 前n/2个 点对的距离和。 如下: 加入第5个节点时,增加的距离就是红色部分+绿色部分。 当前选择的点如果是第偶然个,增加的第一部分距离和选择奇数个的相同。第二部分距离,就是他和上一个点的距离。图中蓝色部分

AC代码:
#include <bits/stdc++.h> #define int long long using namespace std; int a[100050]; signed main(){ int t; cin>>t; a[0] = 0; while(t--){ int n; cin>>n; for(int i = 1 ; i < n ; i ++){ cin>>a[i]; a[i] += a[i-1]; } int sum = 0; // 所有点对的总距离 int pre = 0; // n/2个点对的总距离 for(int i = 1 ; i <= n ; i ++){ if(i%2 == 1) sum += pre; else{ pre += a[n-i/2]-a[i/2-1]; sum += pre; } if(i != n) cout<<sum<<" "; else cout<<sum<<endl; } } }
最新回复(0)