2010 NEERC Eastern Subregional(Ural 1800~1809)解题小结

2015-02-07 02:10:27

  题目很有欧洲赛区的风格... 模拟赛过程不太顺利,习惯于国内的 技巧 and 算法 式解题,而忽略了计算机的最大优势:高速计算,也就是“暴力”!

  然后数学题居多...

A - Murphy's Law(Ural 1800):

  物理题。注意一下单位,l(cm),h(cm),w(转/分钟)

  首先考虑:当重心降到 l/2 的位置时答案就可以确定了(思考),算出时间:t = sqrt(2 * h - l) / g,再算出每转90度需要的时间 : t0 = 90 / (w * 6.0)

  这样就可以算出重心降到 l/2 时面包转了k个90度,根据求出的k(mod 4),判断:若k<1 || k > 3,那么是“butter”,否则就是“bread”

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=0;i<(n);++i)
17 #define REV(i,n) for(int i=(n-1);i>=0;--i)
18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 
27 double l,h,w;
28 
29 int main(){
30     scanf("%lf%lf%lf",&l,&h,&w);
31     if(2 * h < l){
32         printf("butter\n");
33         return 0;
34     }
35     l /= 100.0;
36     h /= 100.0;
37     w *= 6.0;
38     double t = sqrt((2 * h - l) / 9.81) / (90.0 / w);
39     t = t - (int)(t / 4) * 4;
40     if(t < 1 || t > 3)    printf("butter\n");
41     else printf("bread\n");
42     return 0;
43 }
View Code

 

E - The Machinegunners in a Playoff(Ural 1804):

  题目有点长... 其实就是比两场比赛,首先给出第一场比赛的两队进球数,让你算(1)使得A队可能胜,那么A队在第二场比赛至少进几球。(2)使得B队可能胜,那么A队在第二场比赛至多进几球。嫌判断麻烦... 看到比分最多不超过30.. 暴力枚举然后judge QAQ

 1 #include <cstdio>
 2 #include <iostream>
 3 
 4 int T;
 5 int a,b,c,d,flag;
 6 char s[100];
 7 
 8 bool Judge1(int A,int B,int C,int D){
 9     if(A + C == B + D){
10         if(flag == 0){
11             if(C >= B) return true;
12             else return false;
13         }
14         else{
15             if(A >= D) return true;
16             else return false;
17         }
18     }
19     else if(A + C > B + D)
20         return true;
21     else return false;
22 }
23 
24 bool Judge2(int A,int B,int C,int D){
25     if(A + C == B + D){
26         if(flag == 0){
27             if(B >= C) return true;
28             else return false;
29         }
30         else{
31             if(D >= A) return true;
32             else return false;
33         }
34     }
35     else if(B + D > A + C)
36          return true;
37     else return false;
38 }
39 
40 int main(){
41     scanf("%d",&T);
42     while(T--){
43         for(int i = 1; i <= 4; ++i) scanf("%s",s);
44         if(s[0] == 'h') flag = 0;
45         else flag = 1;
46         for(int i = 1; i <= 2; ++i) scanf("%s",s);
47         scanf("%d",&a);
48         for(int i = 1; i <= 3; ++i) scanf("%s",s);
49         scanf("%d",&b);
50         scanf("%s",s);
51         for(int i = 0; i <= 30; ++i){
52             if(Judge1(a,b,i,0)){
53                 c = i;
54                 break;
55             }
56         }
57         for(int i = 30; i >= 0; --i){
58             if(Judge2(a,b,i,30)){
59                 d = i;
60                 break;
61             }
62         }
63         printf("%d %d\n",c,d);
64     }
65     return 0;
66 }
View Code

 

F - Chapaev and a Cipher Grille(Ural 1805):

  一道以天窗密码为背景的题(orz杰哥)... 比赛时YY了一种类似康托的解法... 细节比较多... 推导也蛮多的- =。

  赛后看别人用类似暴力dfs过掉的...

  最终还是延续了比赛时的思路,推导了半天(orz...数学君下线了)... 敲了一个 N×N 的算法。

  ※考虑:n为偶数,选 m = n×n/4 个格子。旋转四次,那么这m个格子都能经旋转获得四个位置,要使每个格子的四个位置都不重复才能覆盖整个图。

  我们给n×n图的左上角1/4的区域编号,然后再把这m个点旋转四次。

  比如就按样例来,n=4 的时候:

    1 2 3 1

    3 4 4 2

    2 4 4 3

    1 3 2 1

  因为题目求的是字典序,所以我们不妨把整个图写成一个长为n×n的序列:1 2 3 1 3 4 4 2 2 4 4 3 1 3 2 1 (总:16个数)

  ※思考:那么我们要在这个序列里面选择1个1,1个2,1个3,1个4... 根据选择的情况我们可以得到一个01序列。

    比如: 1 2 3 1 3 4 4 2 2 4 4 3 1 3 2 1  红色为选择的数)

   01序列:0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 1 ,其实答案就是要输出这个01序列。

   首先可以知道的是,每个数选择一个位置,01序列总共有4*4*4*4=256种,如何求第15个01序列呢?

   下面这个过程就有点像康托了,考虑第一个数:1

    (1)如果这个数不取,那么由后面15个数组成的01序列总:3*4*4*4=192种。

    (2)如果这个数取,那么后面的1都不能取,那么由这16个数可以组成的01序列总:1*4*4*4=64种。(192 + 64 = 256 总数)

   显然(1)的字典序比(2)要小,那么我们只要检查K是否 > 192 就可以判断出取不取这个数了。

    (i)如果K > 192,那么该位标为1(取),K 减去 192。而且后面与该位相同的数都标记为不能再取,剩余的数能构成的01序列总数:48

    (ii)如果K <= 192 ,那么该位标为0(不取),剩余的数能构成的01序列总数:192

   以此类推,我们可以判断出所有的位置,这个01串就被构造出来了。

   ※如果以K = 180为例子:

    <1> 判断第一位:K <= 192,那么第一位数不取,标为0   (此后1234能放的位置个数:3,4,4,4)

    <2> 判断第二位:若这个数不取,则总数为3*3*4*4=144。

        因 K > 144,那么这个数必须取,标为1,且后面所有2都标为不能再取。K 减去 144,为36 (此后1234能放的位置个数:3,0,4,4)

    <3> 判断第三位:若这个数不取,则总数为3*3*4=36。

       因 K > 12,那么这个数必须取,标为1,且后面所有3都标为不能再取。K 减去 36,为0,结束。

    构造出的01串就为:0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0

   ※用点技巧,vis[]来记录每个数还能放的位置个数,不断更新当前能构成的01串总数... 最后会出现一些小问题

    (某些数标记不到,所以如果发现某个数未标记且已经是最后一个了,那么必须取)。O(N×N)

O(N×N):

 1 #include <cstdio>
 2 
 3 int N;
 4 long long K;
 5 int g[110][110],sq[110],vis[110],ans[110];
 6 
 7 inline void Pre(int n){
 8     int k = n / 2,cnt = 0;
 9     for(int i = 1; i <= k; ++i)
10         for(int j = 1; j <= k; ++j)
11             g[i][j] = g[j][n - i + 1] = g[n - i + 1][n - j + 1]
12                 = g[n - j + 1][i] = ++cnt;
13     cnt = 0;
14     for(int i = 1; i <= n; ++i)
15         for(int j = 1; j <= n; ++j)
16             sq[++cnt] = g[i][j];
17 }
18 
19 int main(){
20     scanf("%d%I64d",&N,&K);
21     Pre(N);
22     int k = N * N / 4,len = N * N;
23     long long cur = 1,nxt;
24     for(int i = 1; i <= k; ++i) vis[i] = 4,cur *= 4LL;
25     for(int i = 1; i <= len; ++i) if(vis[sq[i]] > 0){
26         int now = vis[sq[i]];
27         nxt = cur / now;
28         if(now - 1) nxt *= (now - 1);
29         if(K > nxt){
30             K -= nxt;
31             cur -= nxt;
32             ans[i] = 1;
33             vis[sq[i]] = -1;
34         }
35         else{
36             cur = nxt,vis[sq[i]]--;
37             if(vis[sq[i]] == 0) ans[i] = 1; //该数的最后一个,必须取,不取就没了。
38         }
39         if(!K) break;
40     }
41     for(int i = 1; i <= N; ++i){
42         for(int j = 1; j <= N; ++j)
43             printf("%d",ans[(i - 1) * N + j]);
44         puts("");
45     }
46     return 0;
47 }
View Code

 

J - Chapaev and Potatoes:

  将四个土豆重排,使得每个土豆有且仅有另一个土豆与其同一行或同一列,求最少重排几个土豆。

  思考即可知道,最多重排2个土豆的位置。

  发现图为20*20,那么只要枚举重排1个/2个土豆,然后judge即可。

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstring>
 4 
 5 int X[5],Y[5];
 6 
 7 bool Judge(){
 8     int c[5];
 9     memset(c,0,sizeof(c));
10     int A[5] = {0,X[1],X[2],X[3],X[4]};
11     int B[5] = {0,Y[1],Y[2],Y[3],Y[4]};
12     for(int i = 1; i <= 4; ++i){
13         for(int j = i + 1; j <= 4; ++j){
14             if(A[i] == A[j] && B[i] == B[j])
15                 return false;
16             if(A[i] == A[j] || B[i] == B[j])
17                 ++c[i],++c[j];
18         }
19     }
20     for(int i = 1; i <= 4; ++i) if(c[i] != 1) return false;
21     return true;
22 }
23 
24 void Print(){
25     for(int i = 1; i <= 4; ++i)
26         printf("%d %d\n",X[i],Y[i]);
27 }
28 
29 int main(){
30     for(int i = 1; i <= 4; ++i)
31         scanf("%d%d",&X[i],&Y[i]);
32     if(Judge()){
33         Print();
34         return 0;
35     }
36     //move 1
37     for(int i = 1; i <= 4; ++i){
38         int tx = X[i],ty = Y[i];
39         for(int p = 1; p <= 20; ++p){
40             for(int q = 1; q <= 20; ++q){
41                 X[i] = p,Y[i] = q;
42                 if(Judge()){
43                     Print();
44                     return 0;
45                 }
46             }
47         }
48         X[i] = tx,Y[i] = ty;
49     }
50     //move 2
51     for(int i = 1; i <= 4; ++i){
52         for(int j = 1; j <= 4; ++j){
53             int tx1 = X[i],ty1 = Y[i];
54             int tx2 = X[j],ty2 = Y[j];
55             for(int p1 = 1; p1 <= 20; ++p1){
56                 for(int q1 = 1; q1 <= 20; ++q1){
57                     for(int p2 = 1; p2 <= 20; ++p2){
58                         for(int q2 = 1; q2 <= 20; ++q2){
59                             X[i] = p1,Y[i] = q1;
60                             X[j] = p2,Y[j] = q2;
61                             if(Judge()){
62                                 Print();
63                                 return 0;
64                             }
65                         }
66                     }
67                 }
68             }
69             X[i] = tx1,Y[i] = ty1;
70             X[j] = tx2,Y[j] = ty2;
71         }
72     }
73     return 0;
74 }
75                         
View Code

 

 

 

posted @ 2015-02-07 02:27  Naturain  阅读(158)  评论(0编辑  收藏  举报