Contest - 第10届“新秀杯”ACM程序设计大赛网络资格赛 赛后信息(题解)

 

题目列表:

  Problem Id Title
  2145 Problem A ACM-ICPC试炼
  2151 Problem B 找教室
  2152 Problem C 丢失的数列
  2153 Problem D 空想(I)
  2154 Problem E 平面划分
  2155 Problem F 烦恼的李雷
  2156 Problem G 切蛋糕
  2157 Problem H 裁判员


2145 Problem A ACM-ICPC试炼 

基础的输入输出题,自己注意好输入输出格式。

C++

1 #include <iostream>
2 using namespace std;
3 int main() {
4     int a , b , c;
5     while(cin >> a >> b >> c) {
6         cout << a + b + c << endl;
7     }
8     return 0;
9 }

C

1 #include <stdio.h>
2 int main() {
3     int a , b , c;
4     while(~scanf("%d %d %d", &a, &b, &c)) {
5         printf("%d\n", a + b + c);
6     }
7     return 0;
8 }

 

2151 Problem B 找教室 

 

字符串处理问题,注意考虑到所有情况,还有注意输出时候严格按照格式。(主要trick:三教、0层、00号教室、50号教室)

 

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <algorithm>
 6 #include <functional>
 7 #include <vector>
 8 #include <cmath>
 9 #include <string>
10 #include <stack>
11 #include <queue>
12 #include <cstring>
13 using namespace std;
14 int main() {
15     char str[9999];
16     while(~scanf("%s", str)) {
17         if(strlen(str) != 5) {
18             cout << "~_~" << endl;
19             continue;
20         } else if(str[0] != 'X') {
21             cout << "~_~" << endl;
22             continue;
23         } else if(str[1] == '3' || str[1] == '0') {
24             cout << "~_~" << endl;
25             continue;
26         } else if(str[2] <= '0' || str[2] > '6') {
27             cout << "~_~" << endl;
28             continue;
29         }
30         int num = 0;
31         num = str[3] - '0';
32         num = num * 10 + str[4] - '0';
33         if(num < 1 || num > 50) {
34             cout << "~_~" << endl;
35             continue;
36         }
37         cout << "Let's go." << endl;
38     }
39     return 0;
40 }

 

2152 Problem C丢失的数列 

本意就是从一个数列中找到只出现一次的那个数字,今天的题目数据量不大,可以有以下三种思路:

1.sort排序一次后找到那个只出现一次的数字,时间复杂度为O(NlogN);

2.用一个a[10^6]的数组来作为hash表,a[i]表示i值出现的次数,这样扫一遍就知道要求的值是多少,时间复杂度O(N),但比较浪费空间;

3.利用异或的可交换性和可结合性,可以直接得到结果,标程提供此方法代码。

 

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <algorithm>
 6 #include <functional>
 7 #include <vector>
 8 #include <cmath>
 9 #include <string>
10 #include <stack>
11 #include <queue>
12 using namespace std;
13 int main() {
14     int a , b , n;
15     int T;
16     cin >> T;
17     while(T--) {
18         while(~scanf("%d", &n)) {
19             scanf("%d", &a);
20             n--;
21             while(n--) {
22                 scanf("%d", &b);
23                 a = a ^ b;
24             }
25             cout << a << endl;
26         }
27     }
28     return 0;
29 }

2153 Problem D 空想(I)

整行读取输入内容,可以用gets(危险函数,注意gets会吃上一个回车可以用getchar代替吃掉。只要不含大小写字母和数字就可以

 

 

 1 #include "iostream"
 2 #include "algorithm"
 3 using namespace std;
 4 int main() {
 5     int t;
 6     cin >> t;
 7     while (t--) {
 8         int n;
 9         int ok = 0;
10         cin >> n;
11         for (int i = 0; i < n; ++ i) {
12             char s[1000];
13             getchar();
14             gets(s);
15             int temp = 1;
16             for (int j = 0; s[j]; j++ ) {
17                 if((s[j] >= '0' && s[j] <= '9') || (s[j] >= 'a' && s[j] <= 'z')  || (s[j] >= 'A' && s[j] <= 'Z'))
18                     temp = 0;
19             }
20             if (temp == 1)
21                 ok ++;
22         }
23         cout <<  ok  << endl;
24     }
25     return 0;
26 }

 

 

2154 Problem E 平面划分

直线划分平面我们可以发现这么一条规律,对于n条直线划分时,最多可以划分为Ln个平面,那么对于n+1条直线,我们可以这样考虑:每条直线最多可以和其他的每条直线相交一次。那么对于每个新增平面都是对已有的一个平面进行了分割而形成的,所以我们有新增了k个平面即为分割了k个平面,即与k-1个不同的直线相交,那么k<=n;

于是我们有Ln+1<=Ln+ n;我们可以是每一个新增的直线与其他任意一条直线都相交(这是可以做到的),那么我们就可以吧小于号去掉,得到了 Ln+1=Ln+ n(n>0)。

对于n=0时,有Ln = 1;  n>1时有 Ln+1=Ln+ n。

迭代整理可以得到 

Ln = n(n+1)/2 + 1

那么我们考虑V型折线

我们会发现,对于每一个折线,我们都可以看做是两条直线组成的一个系统:这个系统具有如下两个性质:

1、系统内的两条直线只有一个交点。

2、系统内的任意一条直线对系统外的任意直线的影响和独立的直线是相同的。

首先我们可以将折线的拐点放到无限远处。

那么,我们就可以这么考虑,对于n条v型折线,我们可以看做2n条不完全独立的直线,那么在完全独立的情况下,我们有Ln = n(n+1)/2 + 1。那么考虑到折线的特殊性,我们可以得到每一条折线比两条独立的直线少划分了2个平面,那么我们就得到了

Pn = L2n - 2n;

整理可以得到 

Pn = 2n^2 -n +1。

 

 1 #include "iostream"
 2 #include "algorithm"
 3 using namespace std;
 4 int main() {
 5     long long  t;
 6     while (cin >> t) {
 7         cout << 2 * t*t - t + 1 << endl;
 8     }
 9     return 0;
10 }

 

2155 Problem F 烦恼的李雷

方法一:二分法思想。根据题意,函数f(x) = a * x^3 + b * x^2 + c * x  d = 0在a,b,c >= 0的情况下有且只有一个根且单调。于是我们根据函数单调性可知,若f(a) > f(x)且f(b) < f(x)的话,则有b < x < a,符合二分性质。我们用1-1e6作为二分界限即可。复杂度O(log(n))。

方法二(Vking提供):求一元三次方程 f(x) = a * x^3 + b * x^2 + c * x  d ,可知f(0)处必小于0,所以可从0处开始枚举,但这时枚举有技巧,要用到缩短步长的方法,先设步长step为10^6,然后在枚举到f(x)即将大于0处缩短步长,将步长缩短为原来的10倍,然后继续向前枚举,重复上述循环,由于考虑到精度问题,所以可以将最后的步长定的比较小来保证精确度,如标程中将最终步长定为10^-7。

 

 1 /****************************************/
 2 /*****            Desgard_Duan        *****/
 3 /****************************************/
 4 //#pragma comment(linker, "/STACK:102400000,102400000")
 5 #define _CRT_SECURE_NO_WARNINGS
 6 #include <iostream>
 7 #include <cstdio>
 8 #include <cstdlib>
 9 #include <cstring>
10 #include <string>
11 #include <sstream>
12 #include <algorithm>
13 #include <stack>
14 #include <map>
15 #include <queue>
16 #include <vector>
17 #include <set>
18 #include <functional>
19 #include <cmath>
20 #include <numeric>
21 #include <iomanip>
22 
23 #define eps 1e-9
24 using namespace std;
25 
26 inline void get_val(int &a) {
27     int value = 0, s = 1;
28     char c;
29     while ((c = getchar()) == ' ' || c == '\n');
30     if (c == '-') s = -s;
31     else value = c - 48;
32     while ((c = getchar()) >= '0' && c <= '9')
33         value = value * 10 + c - 48;
34     a = s * value;
35 }
36 
37 int main () {
38     double a, b, c, d;
39     while (~scanf ("%lf %lf %lf %lf", &a, &b, &c, &d)) {
40         double l = 0.0, r = 1e6 + 0.0, mid, x;
41         while (r - l > eps) {
42             mid = (l + r) / (double)2.0;
43             x = a * mid * mid * mid + b * mid * mid + c * mid;
44             if (x >= d) {
45                 r = mid;
46             } else {
47                 l = mid;
48             }
49         }
50         printf ("%.4lf\n", r);
51     }
52     return 0;
53 }

 

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <algorithm>
 6 #include <functional>
 7 #include <vector>
 8 #include <cmath>
 9 #include <string>
10 #include <stack>
11 #include <queue>
12 using namespace std;
13 double a , b , c , d;
14 double f(double x) {
15     return a * x * x * x + b * x * x + c * x - d;
16 }
17 int main() {
18     while(~scanf("%lf %lf %lf %lf", &a, &b, &c, &d)) {
19         double x = 0;
20         double step = 1000000;
21         while(step >= 0.0000001) {
22             while(f(x + step) < 0.00)
23                 x += step;
24             step /= 10;
25         }
26         printf("%.4lf\n", x);
27     }
28     return 0;
29 }

 

2156 Problem G 切蛋糕

对于已知的两个数n,m,我们不妨假设n > m,

令蛋糕的大小ans = n*m,再将ans分解成n块

现在我们要解决的就是如何再分这n块使得所有数都能配对成m个ans/m;

记现在状态为(n,m);

显然,我们这时已经得到(int)n / m 堆 含有m块蛋糕(每块蛋糕重为m)的堆了,即现在分好的堆数为(int)(n / m) * m;

那么下一步是拆分剩下的n % m块蛋糕,显然我们的目的要将它们全部填充到原来的m块蛋糕中使得m 最终变成n

那么此时的状态为(m,n % m;//你可以理解为此时n = m,m = n % m

是不是很像gcd?

当我们最终进行到(k,0)时,意味着,在上一个状态,我们已经将所有蛋糕分组好,所以不需要再分了;

显然,由上面得知每次划分多出来的个数为(int)(n / m) * m;

只需要在gcd中每次累加即可

算法的复杂度为O(logn);

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <algorithm>
 4 #include <string>
 5 #include <stack>
 6 #include <queue>
 7 #include <vector>
 8 #include <map>
 9 #include <set>
10 
11 using namespace std;
12 long long ans;
13 void gcd(long long a, long long b) {
14     if (b != 0) {
15         ans += b * (a / b);
16         return gcd(b, a % b);
17     } else return;
18 }
19 int main() {
20     //freopen("data.out", "w", stdout);
21     //freopen("data.in", "r", stdin);
22     cin.sync_with_stdio(false);
23     long long a, b;
24     while (cin >> a >> b) {
25         ans = 0;
26         if (a < b) swap(a, b);
27         gcd(a, b);
28         cout << ans << endl;
29     }
30     return 0;
31 }

 

2157 Problem H 裁判员

模拟ACM比赛的情况,注意提交为总次数,正确提交没有罚时,某题未通过也不计罚时排名时优先AC题数,通过数目相同,按时间升序排列

 

 

 1 #include "iostream"
 2 #include "algorithm"
 3 using namespace std;
 4 
 5 typedef struct {
 6     char  name[30];
 7     int ok[5];
 8     int score[5];
 9     int num;
10     int time;
11 } student;
12 student stu[1000];
13 
14 int  cmp(student a, student b) {
15     if (a.num != b.num)
16         return a.num > b.num;
17     if (a.num == b.num)
18         return a.time < b.time;
19 }
20 
21 int main() {
22     int  t;
23     cin >> t;
24     memset (stu, 0, sizeof(stu));
25     for (int i = 0; i < t; ++ i) {
26         cin >> stu[i].name >>  stu[i].ok[0] >>  stu[i].score[0] >> stu[i].ok[1] >> stu[i].score[1] 
         >> stu[i].ok[2] >> stu[i].score[2] >> stu[i].ok[3] >> stu[i].score[3]; 27 for (int j = 0; j < 4; ++ j) { 28 if (stu[i].score[j] != 0) { 29 stu[i].time += (stu[i].ok[j] - 1) * 20 + stu[i].score[j] ; 30 stu[i].num ++; 31 } 32 } 33 } 34 sort(stu, stu + t, cmp); 35 cout << stu[0].name << " " << stu[0].num << " " << stu[0].time << endl; 36 return 0; 37 }

 

传送门:

Contest - 第10届“新秀杯”ACM程序设计大赛网络资格赛 赛后信息(晋级名单):http://www.cnblogs.com/Destiny-Gem/p/4084180.html 

 

 


最后感谢此次的命题人:

段昊宇(Desgard_Duan)、朱吴帅(JM)、叶勐(MG)、王浩宇(stdiohero)、叶鹏(yeahpeng)、王驰(WID)同学。

感谢验题人:

段昊宇、朱吴帅、王驰、叶鹏、王浩宇同学。

感谢撰写题解者:

滕雄(Vking)【A、B、C、F】、胡建(UsedRose)【D、H】、段昊宇(Desgard_Duan)【F】、王浩宇(stdiohero)【E】、张羿辰(RUO)【G】同学。

 

Desgard_Duan

2014.11.8

 

 


posted @ 2014-11-08 23:49  Desgard_Duan  阅读(857)  评论(0编辑  收藏  举报