Codeforces Round #270 solution

A.Design Tutorial: Learn from Math

题意:给你一个大于12小于1e6的数,让你把这个数表示为两个合数之和。
解法:筛素数后枚举一个合数判断另一个是否是合数。
代码:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <map>
 5 #include <string>
 6 #include <set>
 7 #include <algorithm>
 8 using namespace std;
 9 
10 const int N = 1000010;
11 
12 int p[N];
13 
14 void init() {
15     for(int i = 2; i * i <= N; i++) {
16         if(p[i] == 0) {
17             for(int j = i * i; j < N; j += i) p[j] = 1;
18         }
19     }
20 }
21 
22 int a[N];
23 
24 int main() {
25     int n;
26     init();
27     scanf("%d", &n);
28     for(int i = 4; i < n; i++) {
29         if(p[i] && p[n - i]) { printf("%d %d\n", i, n - i); return 0; }
30     }
31 
32     return 0;
33 }
View Code

 

B.Design Tutorial: Learn from Life

题意:有一些人在1楼要坐电梯,他们分别要前往不同的楼层,电梯最多只能装k个人,电梯从a层开到b层的时间为|a-b|,中间上下人的时间忽略不计。问最少花费多久可以把所有人都运到他们要去的楼层。

解法:明显我们会按去的楼层的大小序来运送,不妨从小到大。然后未必每次运最多的人最优,样例很厚道的给出了反例。我们设f[x]为把去往楼层前x小的人运送完毕的花费,枚举这次运多少人dp即可。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <map>
 5 #include <string>
 6 #include <set>
 7 #include <algorithm>
 8 using namespace std;
 9 
10 const int N = 2010;
11 
12 int f[N];
13 int a[N];
14 
15 int main() {
16     int n, k;
17     scanf("%d%d", &n, &k);
18     for(int i = 0; i < n; i++) scanf("%d", &a[i]);
19     sort(a, a + n);
20     for(int i = 1; i <= n; i++) f[i] = 1000000000;
21     for(int i = 1; i <= n; i++) {
22         for(int j = 1; j <= k; j++) {
23             if(i >= j) f[i] = min(f[i], f[i - j] + 2 * (a[i - 1] - 1));
24         }
25     }
26     printf("%d\n", f[n]);
27 
28     return 0;
29 }
View Code

 

C.Design Tutorial: Make It Nondeterministic

题意:有n个人,他们的名字由两个长度不超过50的字符串构成,每个人可以任选其一来代表自己。现在给出这n个人按照他们选择的名字按字典序从小打到的一个排序,问这个排序是否是可能出现的。
解法:我们从名字字典序最小的那个人开始看,显然是使用字典序小的那个比较好,然后对于后面的在满足他选择的这个名字的字典序大于前面那个人的字典序的情况下选择较小的那个,如果不可能那么这个排序不可能出现。详见代码。
代码:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <map>
 5 #include <string>
 6 #include <set>
 7 #include <algorithm>
 8 using namespace std;
 9 
10 const int N = 200010;
11 struct name {
12     char s[52];
13     int id;
14 }p[N];
15 
16 bool cmp(const name &a, const name &b) {
17     return strcmp(a.s, b.s) < 0;
18 }
19 
20 int k[2][N], a[N];
21 
22 int main() {
23     int n;
24     scanf("%d", &n);
25     for(int i = 0; i < n; i++) {
26         scanf("%s%s", p[2 * i].s, p[2 * i + 1].s);
27         p[2 * i].id = p[2 * i + 1].id = i + 1;
28     }
29     sort(p, p + 2 * n, cmp);
30     for(int i = 0; i < 2 * n; i++) {
31         if(k[0][p[i].id] == 0) k[0][p[i].id] = i + 1;
32         else k[1][p[i].id] = i + 1;
33     }
34     for(int i = 0; i < n; i++) scanf("%d", &a[i]);
35     int now = 0;
36     int f = 0;
37     for(int i = 0; i < n; i++) {
38         if(k[0][a[i]] > now) now = k[0][a[i]];
39         else if(k[1][a[i]] > now) now = k[1][a[i]];
40         else { f = 1; break; }
41     }
42     if(f == 0) printf("YES\n");
43     else printf("NO\n");
44 
45     return 0;
46 }
View Code

 

D.Design Tutorial: Inverse the Problem

题意:现在给你一个n*n的数组d表示一棵带正权的树上任意两点间距离,问这样的树是否存在。
解法:如果我们找到现在这个图上最长的距离,那么这条边的两个端点必然是叶子。设一个端点为x,我们找到一个端点为x的最小的距离,假设满足最小距离的另一个端点为y,然后我们只需要判断是否所有的端点都满足d[x][y] + d[y][i] = d[x][i]。如果满足,我们可以删去x这个点继续判断,否则这棵树不存在。注意要先判断对角线全0和对称。(因为某些原因我写了个set排序导致一直tle。。真是sad。。)
P.S. 思考可以发现我们不排序直接去进行这个判断也是对的,原因大家自己思考下吧,可以考虑下删掉这条边之后剩下的两颗子树实际对于这个判断都是满足的。
代码:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <map>
 5 #include <vector>
 6 #include <string>
 7 #include <set>
 8 #include <algorithm>
 9 using namespace std;
10 
11 const int N = 2010;
12 const int oo = 1000000000 + 10;
13 int a[N][N];
14 int n;
15 
16 inline bool check() {
17     for(int i = 0; i < n; i++) {
18         if(a[i][i] != 0) return false;
19         for(int j = 0; j < n; j++) {
20             if(a[i][j] != a[j][i]) return false;
21             if(i != j && a[i][j] == 0) return false;
22         }
23     }
24     return true;
25 }
26 
27 vector< pair<int, int> > s;
28 
29 int u[N];
30 
31 inline bool gao(int x) {
32     int now = oo, k;
33     for(int i = 0; i < n; i++) {
34         if(i == x || u[i] == 1) continue;
35         if(a[x][i] < now) {
36             k = i;
37             now = a[x][i];
38         }
39     }
40     for(int i = 0; i < n; i++) {
41         if(i == x || u[i] == 1) continue;
42         if(a[x][k] + a[k][i] != a[x][i]) return false;
43     }
44     return true;
45 }
46 
47 inline int rd()
48 {
49     char ch = getchar();
50     int data = 0;
51     while (ch < '0' || ch > '9')
52         ch = getchar();
53     do
54     {
55         data = data*10 + ch-'0';
56         ch = getchar();
57     } while (ch >= '0' && ch <= '9');
58     return data;
59 }
60 
61 int main() {
62     scanf("%d", &n);
63     for(int i = 0; i < n; i++) {
64         for(int j = 0; j < n; j++) a[i][j] = rd();
65     }
66     if(!check()) { printf("NO\n"); return 0; }
67     for(int i = 0; i < n; i++) {
68         for(int j = i + 1; j < n; j++) {
69             s.push_back(make_pair(-a[i][j], i * 10000 + j));
70         }
71     }
72     int flag = 0;
73     sort(s.begin(), s.end());
74     for(int i = 0; i < (int)s.size(); i++) {
75         int aa = s[i].second / 10000, bb = s[i].second % 10000;
76         if(u[aa] == 1 || u[bb] == 1) continue;
77         if(gao(aa) == false || gao(bb) == false) { flag = 1; break; }
78         u[aa] = u[bb] = 1;
79     }
80     if(flag) printf("NO\n");
81     else printf("YES\n");
82 
83     return 0;
84 }
View Code

 

 
posted @ 2014-09-29 13:58  shiina mashiro  阅读(258)  评论(1编辑  收藏  举报