2016 寒假训练赛(一) 自我总结

来源:互联网 发布:中国期刊网络出版总库 编辑:程序博客网 时间:2024/06/05 17:43

时间:2017-1-18 13:00 - 17:00

全场共七题,四个小时出了四题,反思总结如下:

1.太过追求名次,一道题自己没思路看到很多人都过掉就会感觉慌张,下一场训练赛一定要仔细读题,不要放过每一个细节,另外没有吃透每一道题前不要看rank榜。

2.以后第一次没做出的题有了思路后都要写博客自己再写一遍,加深印象。


下面是题目+思路+代码:

Problem A

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 44   Accepted Submission(s) : 42

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

对于一个01字符串,做如下定义: 如果该串包含奇数个1,则说明它是不平等串,如果包含偶数个1,则说明它是平等串。现在已知一个01字符串S,它的最后一位被替换掉了,如果S是平等串,则末位将被'f'替换,否则将被'u'替换,现在给你一个被替换过的串,你要做的是找出原串并输出。

Input

输入包含多组数据,以"#"结束
每组数据包含一个被替换过的01字符串,串的长度不超过1000.

Output

对于每组数据,输出原串。

Sample Input

101f010010u1f000f110100101u#

Sample Output

101001001011100001101001010

签到题,水~

#include <bits/stdc++.h>using namespace std;const int maxn = 1001;char str[maxn];int main(){while(scanf("%s",str) != EOF){if(str[0] == '#')break;int i,num_1 = 0;int len = strlen(str);for(i=0 ;i<len-1 ;i++){if(str[i] == '1')num_1++;}if(str[len-1] == 'f' && num_1&1){str[len-1] = '1';}else if(str[len-1] == 'u' && !(num_1&1)){str[len-1] = '1';}else{str[len-1] = '0';}puts(str);}return 0;}


Problem B

Time Limit : 3000/5000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 129   Accepted Submission(s) : 28

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

众所周知Chaos是个大学霸,他每次考试都是满分,对此Chaos感到很无聊。这天他在纸上写了n个数字,然后想:我能不能考出这些分数呢?假设Chaos初始时可以考到的分数是m分,他第i次考试最多能进步max(k - i, 0)分(i从1开始)。因为Chaos是个学霸,他总能控制他考到的分数x,只要x不超过他所能考到的分数上限。
即假设他第i次考得的分数是Xi, 则有0≤Xi≤Xi-1+max (k - i,0 )。Chaos可以考无数次试。
现在给你Chaos写下的n个分数,请你判断这些分数Chaos是否全部有可能考到(不要求按顺序)
都说了Chaos每次考试都是满分,那么他是怎么能够再进步呢?Chaos对此表示,作为一个学霸,他是无所不能的。

Input

输入包含多组数据
对于每组数据,第一行包括三个整数n,m和k(0≤n,m,k≤106
第二行包括n个整数ai(0≤ai≤1014),代表Chaos想要考到的分数.

Output

对于每组数据,如果Chaos能考到全部他想要考出的分数,输出"Yes",否则输出"Impossible",不包括引号

Sample Input

5 100 1063 59 140 30 35 0 11 2 3 4 1000000000000

Sample Output

YesImpossible

开始卡了很久,一直不懂题意,忽略了一个重要条件:0≤Xi≤Xi-1+max (k - i,0 ),也就是说每一次的分数可以是0~最大分数中的任意值,所以只需要判断每一次的当前分加上能加分的最大分(等差数列求和)与目标最大分数的关系。

而小于初始分的目标分可以直接忽略不参与排序。

代码:

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6 + 1;long long grade[maxn];long long n,m,k;int main(){int num,i;long long t;while(scanf("%lld%lld%lld",&n,&m,&k) != EOF){num = 0;for(i=0 ;i<n ;i++){scanf("%lld",&t);if(t>m)grade[num++] = t;}sort(grade,grade+num);if(k)k--;for(i=num-1 ;i>=0 ;i--){if(grade[i] > m + (k*(k+1)/2)){break;}else{m += k;k--;}}if(i<0){printf("Yes\n");}else{printf("Impossible\n");}}return 0;}

Problem C

Time Limit : 3000/2000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 66   Accepted Submission(s) : 30

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

 
OSU是一种音乐节奏类打击游戏,游戏者需跟随音乐节奏控制键鼠点击屏幕上出现的各种图形,根据图形的不同,操作方式也不一样,为了使问题更简单,在本题目中,只会出现以下3种不同的图形,并且把所有的圆都视作点
1.Circle Click 在屏幕上(x, y)出现一个圆,操作者需要移动鼠标到(x, y)处并点击
 
2.Segment Move 在屏幕(x1, y1)处出现线段的起点,(x2, y2)处出现线段的终点,操作者需要移动鼠标到坐标(x1, y1)处,保持click,鼠标跟随线段移动至(x2, y2)处
 
3.Back Move 在屏幕(x1, y1)处出现线段的起点,(x2, y2)处出现线段的终点,操作者需要移动鼠标到坐标(x1, y1)处,保持click,鼠标跟随线段移动至(x2, y2)处再返回(x1, y1)
 
现已知鼠标的初始位置在(0, 0)处,按顺序给出N个图形的类别和坐标,求操作者需要移动鼠标的距离之和至少是多少

Input

输入第一行是一个正整数T (T≤100 ),表示有T组数据
对于每组数据,输入第一行是一个正整数N (1≤N≤100 ),表示有N个图形出现
接下来N行,第i行表示第i个出现的图形信信,表达方式有3种:
1 x y 表示该图形是一个Circle Click,坐标是(x, y)
2 x1 y1 x2 y2 表示该图形是一个Segment Move,线段起点是(x1, y1), 终点是(x2, y2)
3 x1 y1 x2 y2表示该图形是一个Back Move,线段起点是(x1, y1), 终点是(x2, y2)
所有坐标的范围都是[-100, 100]

Output

对于每组数据,先输出“Case k: ”,k表示第k组数据,然后输出操作者需要移动鼠标的距离之和的最小值,精确到小数点后6位.

Sample Input

311 1 121 1 02 1 1 1 221 1 03 1 1 1 2

Sample Output

Case 1: 1.414214Case 2: 3.000000Case 3: 4.000000

题目很长,开始看到最优解就先入为主的以为题目很难.....感觉比求最近点对还要难,情况很多,但其实只是一个很水的模拟题,很坑,题目最后有说是按顺序给图形。

代码:

#include <bits/stdc++.h>using namespace std;int main(){int T,_=1;scanf("%d",&T);while(T--){int n,i,type,xx = 0,yy = 0;int x1,y1,x2,y2;double ans = 0;scanf("%d",&n);for(i=0 ;i<n ;i++){scanf("%d",&type);if(type == 1){scanf("%d%d",&x1,&y1);ans += sqrt((x1-xx)*(x1-xx) + (y1-yy)*(y1-yy));xx = x1,yy = y1;}else if(type == 2){scanf("%d%d%d%d",&x1,&y1,&x2,&y2);ans += sqrt((x1-xx)*(x1-xx) + (y1-yy)*(y1-yy));ans += sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));xx = x2,yy = y2;}else{scanf("%d%d%d%d",&x1,&y1,&x2,&y2);ans += sqrt((x1-xx)*(x1-xx) + (y1-yy)*(y1-yy));ans += 2*sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));xx = x1,yy = y1;}}printf("Case %d: %f\n",_++,ans); }return 0;}

Problem D

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 57   Accepted Submission(s) : 37

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

一个k位超级素数(Super prime)是指一个k位正整数,它的前1位,前2位, …, 前k位均为素数。例如,239是个3位超级素数,因为2,23,239均为素数。现在的问题是要让输出所有的k位超级素数。
PS:素数是指因子只有1和它本身的数

Input

输入第一行是一个正整数T( T≤100),表示有T组数据。
接下来T行每行包括一个k(1≤k≤8 )。

Output

对于每组数据,输出所有k位超级素数,每个超级素数占一行,按升序输出。

Sample Input

11

Sample Output

2357

思路:深搜,每一个超级素数都是由前一个比其少一位的超级素数*10加上新的位数得到,因为数据量小,所以可以直接深搜输出,设置上下界避免输出超界。

代码:

#include <bits/stdc++.h>using namespace std;int u,v;bool isprime(int x){if(x == 0 || x == 1)return false;int i;for(i=2 ;i<=(int)sqrt(x) ;i++){if(x %i == 0)return false;}return true;}void dfs(int x){int i,num;for(i=0 ;i<=9 ;i++){num = x + i;if(isprime(num)){if(num > v)return;if(num>=u)printf("%d\n",num);dfs(num*10);}}}int main(){int T,n,i;scanf("%d",&T);while(T--){scanf("%d",&n);u = 1;for(i=1 ;i<n ;i++){u *= 10;}v = u*10 - 1;dfs(0);}return 0;}

Problem E

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 96   Accepted Submission(s) : 40

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

给出n,计算

Input

输入第一行是一个正整数T,表示有T组数据
每组数据包含一个正整数n (n<231 )

Output

对于每组数据,输出一个整数表示答案

Sample Input

212

Sample Output

15

Statistic | Submit | Back

水题,循环节为20,所以每个数对20取模,然后套公式sum = (n)*(n+1)(2*n+1)/6即可。

另外好像还有很多其他解法,但我认为打表后找循环节算是很方便的解法了。

代码:

#include <bits/stdc++.h>using namespace std;int main(){int T,n,ans;scanf("%d",&T);while(T--){scanf("%d",&n);n %= 20;ans = n*(n+1)*(2*n+1)/6;ans %= 10;printf("%d\n",ans);}return 0;}

Problem F

Time Limit : 3000/2000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 57   Accepted Submission(s) : 28

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

笨蛋君得到了一堆糖果,他想将糖果分给他的两个好朋友BD666和BD888。他在地上放n个糖果,每个糖果都有它的价值,分别是v1,v2,v3,v4...vn。笨蛋君先让BD666在地上捡起一部分糖果(不能全捡),随后BD888捡起剩下的全部糖果。然后笨蛋君会检测两人手中糖果的总价值是不是相等。要注意的是笨蛋君是用异或操作来看一个人获得的总价值的。比如BD666捡了3块价值为v1,v2,v3的糖果,笨蛋君就认为他获得的价值是v1 xor v2 xor v3。如果BD666和BD888获得的总价值不相等的话,笨蛋君就会认为BD666破坏了分配的公平性。
然后问题就来了,BD666想问你在不破坏分配公平的情况下,自己能获得的最大的糖果数量是多少。
PS: 异或运算即C++中的“^ ”运算符,特点是按位运算,相同为0,不同为1,例如(1100)2^ (1010)2==(0110)2

Input

输入第一行是一个正整数T,表示有T组数据(1≤T≤100 )。
对于每组数据,第一行是一个正整数n(2≤n≤100000 )
第二行包含n个正整v1, v2, v3, v4...vn. (vi<231 )

Output

输出BD666所能获得的最大糖果数量,如果BD666无论如何都不能让笨蛋君满意的话(即破坏了分配的公平性),输出-1。

Sample Input

221 221 1

Sample Output

-11

如果异或和相等,则两个和再异或一定为零,所以可以把所有的数都异或起来,如果值不为零,则输出-1,否则输出n-1,因为若x ^ y == 0,那么x == y,则n个数,任意n-1个数全部异或的和一定与剩下的那个数相等。

代码:

#include <bits/stdc++.h>using namespace std;#include <bits/stdc++.h>using namespace std;int main(){int T;scanf("%d",&T);while(T--){int n,i,sum = 0,t;scanf("%d",&n);for(i=0 ;i<n ;i++){scanf("%d",&t);sum ^= t;}if(sum == 0)printf("%d\n",n-1);elseprintf("-1\n");}return 0;}


Problem G

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/102400K (Java/Other)
Total Submission(s) : 62   Accepted Submission(s) : 18

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

You are given an integer array s[] and are asked to counthow many positions a, b, c and d satisfy the condition: s[a] + s[b] + s[c] == s[d].
Note that a, b, c, and d do not need to be distinct.

Input

The first line of input contains an integer T, indicates the cases.
Each of the next Tblocks contains an integer n first (0< n ≤1000 ), the length of the array s[], following with n integers representing s[] (0≤ si≤100000 ).

Output

Output Tlines each contains the answer required. You'd better use 'long long' instead of 'int'.

Sample Input

440 0 0 021 341 10 100 11113

Sample Output

256160
这道题才是最气的,之前做过一道完全相当于一模一样的题,之前的思路就错了一直WA,然后今天又走的错误的老思路,超时到底。回归正题,这题可以移项,然后两两一对来降低复杂度,然后一组用HASH来存数目,一组直接映射查找,累加数目即可。

代码:

#include <bits/stdc++.h>using namespace std;const int maxn = 1010;int v[maxn];int Hash[200005];int main(){int T;scanf("%d",&T);while(T--){int i,j,n;scanf("%d",&n);for(i=0 ;i<n ;i++){scanf("%d",&v[i]);}memset(Hash,0,sizeof(Hash));for(i=0 ;i<n ;i++){for(j=0 ;j<n ;j++){Hash[v[i]+v[j]]++;}}long long ans = 0;for(i=0 ;i<n ;i++){for(j=0 ;j<n ;j++){if(v[i]-v[j]>=0){ans += Hash[v[i]-v[j]]; }}}printf("%lld\n",ans);}return 0;}
0 0
原创粉丝点击