The 14th Zhejiang University Programming Contest(未完工)

链接:The 14th Zhejiang University Programming Contest

【2014/05/10】今下午和队友一起做了这套题,最后的Rank差不多这样,AC数目4道。现在就先把做了的4道题的心得写下来,剩下几道题以后会更新。

【2014/05/12】今天完成了Diablo III这道题,看了别人的解题报告后,真是自愧不如啊,dp果然是神奇的东西。

【2014/05/13】今天完成了Calcuate the Function这道题,矩阵真是强大,只怪线性代数学的撇。=_=#


 

A - Elevator

这是一道最大的水题,zzy学长一看题就敲了,然后就pass了。代码如下:

 1 /*
 2 ** ZOJ 3767 Elevator
 3 ** Created by Rayn @@ 2014/05/10
 4 */
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <algorithm>
 8 using namespace std;
 9 
10 int main() {
11 
12     int t;
13     scanf("%d", &t);
14     while(t--)
15     {
16         int n, m, sum = 0;
17         scanf("%d%d", &n, &m);
18         for (int i=0; i<n; i++)
19         {
20             int x;
21             scanf("%d", &x);
22             sum += x;
23         }
24         if (sum > m)
25         {
26             printf("Warning\n");
27         }
28         else
29         {
30             printf("Safe\n");
31         }
32     }
33     return 0;
34 }
View Code

B - Continuous Login

【题意】给你一个整数N,然后将N表示为若干段1~K连续的数段的和,问你最小的段数,输出几段的K。

【思路】开始看这道题觉得是贪心或者DP吧,然后我想了一下觉得不会出现第四段,最后打了一下表发现果然最多只有三段。于是这样就可以暴力了。先把连续数段和处理出来,然后直接lower_bound查找第一段数,符合就直接输出,不行就枚举两段的和三段的。最后60MS过了,按道理来说复杂度很高的。下面是代码:

 

 1 /*
 2 ** ZOJ 3768 Continuous Login
 3 ** Created by Rayn @@ 2014/05/10
 4 */
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <algorithm>
 8 #define INF 0x3f3f3f3f
 9 using namespace std;
10 int a[50000], sz;
11 
12 void init()
13 {
14     for (int i = 1; (i*(i+1)/2)<=123456789;i++)
15     {
16         a[i] = i*(i+1)/2;
17         sz = i;
18     }
19     sz++;
20 }
21 
22 int main()
23 {
24     init();
25     int t;
26     scanf("%d",&t);
27     while(t--)
28     {
29         int n;
30         scanf("%d",&n);
31         int k = lower_bound(a+1,a+sz,n) - a;
32         int flag=0;
33         if (a[k]==n)
34         {
35             flag = 1;
36             printf("%d\n",k);
37         }
38         else
39         {
40             for (int i = 1; a[i] <= n; i++)
41             {
42                 int l = n - a[i];
43                 int j = lower_bound(a+1,a+sz,l) - a;
44                 if (a[j]== l)
45                 {
46                     printf("%d %d\n",i,j);
47                     flag = 1;
48                     break;
49                 }
50 
51             }
52         }
53         if (!flag)
54         {
55             for (int i = 1; a[i]<= n; i++)
56             {
57                 for (int j = 1; a[i]+a[j]<=n && !flag;j++)
58                 {
59                     int l = n - a[i] - a[j];
60                     int k = lower_bound(a+1,a+sz,l) - a;
61                     if (a[k] == l)
62                     {
63                         printf("%d %d %d\n",i,j,k);
64                         flag = 1;
65                         break;
66                     }
67                 }
68             }
69         }
70     }
71     return 0;
72 }
View Code

 

C - Diablo III

【题意】yuzhi在玩游戏"大菠萝3",有13个武器插槽,装备如下 {"Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist", "Legs", "Feet", "Finger", "Shield", "Weapon", "Two-Handed"},"Finger"可以戴两个,还有戴了"Two-Handed"就不能戴"Shield"和"Weapon"。然后每个武器都有两个属性: Damage和Toughness,要求在Toughness不小于M的情况下,怎样选择戴装备让Damage最大。

【思路】开始一直没有读懂题,其实这题就是一个包含特例的01背包问题,每个武器可以戴一个,关键是在于"Finger"可以戴两个,所以要先对"Finger"的状态进行处理。设置dp[i][j]代表佩戴前i件装备,Toughness为j的状况下最大的Damage。还有就是"Two-Handed"的状态不能从"Shield", "Weapon"转移过来,因为这两个不能共存。

代码如下:

 1 /*
 2 ** ZOJ 3769 Diablo III
 3 ** Created by Rayn @@ 2014/05/12
 4 ** 背包
 5 */
 6 #include <cstdio>
 7 #include <iostream>
 8 #include <vector>
 9 #include <map>
10 #include <cstring>
11 #include <algorithm>
12 using namespace std;
13 const int MAXM = 50000 + 10;
14 
15 struct Equip {
16     int D, T;
17     Equip(int d = 0, int t = 0): D(d), T(t) {}
18 };
19 int dp[13][MAXM];
20 map<string, int> equip_id;
21 
22 void Init()
23 {
24     equip_id["Finger"] = 0;
25     equip_id["Head"] = 1;
26     equip_id["Shoulder"] = 2;
27     equip_id["Neck"] = 3;
28     equip_id["Torso"] = 4;
29     equip_id["Hand"] = 5;
30     equip_id["Wrist"] = 6;
31     equip_id["Waist"] = 7;
32     equip_id["Legs"] = 8;
33     equip_id["Feet"] = 9;
34     equip_id["Shield"] = 10;
35     equip_id["Weapon"] = 11;
36     equip_id["Two-Handed"] = 12;
37 }
38 inline void takemax(int &a, int b)
39 {
40     if(a < b) a = b;
41 }
42 int main()
43 {
44     int T, N, M;
45 
46     Init();
47     scanf("%d", &T);
48     while(T--)
49     {
50         scanf("%d%d", &N, &M);
51 
52         vector<Equip> E[13];
53         string s;
54         for(int i=0; i<N; ++i)
55         {
56             int d, t;
57             cin >> s >> d >> t;
58             E[equip_id[s]].push_back(Equip(d,t));
59         }
60         E[0].push_back(Equip(0, 0));
61         memset(dp, -1, sizeof(dp));
62         dp[0][0] = 0;
63         for(int i=0; i<(int)E[0].size(); ++i)
64         {
65             for(int j=0; j<i; ++j)
66             {
67                 takemax(dp[0][min(E[0][i].T + E[0][j].T, M)], E[0][i].D + E[0][j].D);
68             }
69         }
70         int ans = -1;
71         for(int i=1; i<=12; ++i)
72         {
73             int p = (i == 12)? 9 : i - 1;
74             memcpy(dp[i], dp[p], sizeof(dp[p]));
75             for(int k=0; k<E[i].size(); ++k)
76             {
77                 for(int j=0; j<=M; ++j)
78                 {
79                     if(dp[p][j] < 0)
80                         continue;
81                     takemax(dp[i][min(j + E[i][k].T, M)], dp[p][j] + E[i][k].D);
82                 }
83             }
84             takemax(ans, dp[i][M]);
85         }
86         printf("%d\n", ans);
87     }
88     return 0;
89 }
View Code

D - Ranking System

【题意】给你一些人的ID,加入时间,积分。要求给这些人分配等级(LV1 ~ LV6,具体分配规则见题目)。

【思路】这道题也是一道大水题,就根据他的规则去模拟就行了,开始看了题之后就去敲,开始感觉自己写的很挫,还排了两次序,幸好最后1A了。下面是代码:

 

 1 /*
 2 ** ZOJ 3770 Ranking System
 3 ** Created by Rayn @@ 2014/05/10
 4 */
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <algorithm>
 8 using namespace std;
 9 const int MAX = 2005;
10 
11 struct Member{
12     int num;
13     int ID, date, score;
14     int degree;
15 } man[MAX];
16 
17 int cmp1(const Member& A, const Member &B)
18 {
19     if(A.score != B.score)
20         return A.score < B.score;
21     if(A.date != B.date)
22         return A.date > B.date;
23     else
24         return A.ID > B.ID;
25 }
26 int cmp2(const Member& A, const Member &B)
27 {
28     return A.num < B.num;
29 }
30 int main() {
31 
32 #ifdef HotWhite
33     //freopen("in.txt", "r", stdin);
34 #endif
35 
36     int T, n;
37     scanf("%d", &T);
38     while(T--)
39     {
40         memset(man, 0, sizeof(man));
41         scanf("%d", &n);
42         int cnt = 0;
43         for(int i=0; i<n; ++i)
44         {
45             int y,m,d;
46             scanf("%d %d/%d/%d %d", &man[i].ID, &y,&m,&d, &man[i].score);
47             man[i].num = i+1;
48             man[i].date = d + m*100 + y*10000;
49             if(man[i].score > 0)
50                 cnt++;
51         }
52         sort(man, man+n, cmp1);
53         /*
54         for(int i=0; i<n; ++i)
55         {
56             printf("%d %d %d\n", man[i].ID, man[i].date, man[i].score);
57         }
58         //*/
59         int lv[7];
60         lv[1] = n - cnt;
61         lv[3] = (int)(cnt * 0.3);
62         lv[4] = (int)(cnt * 0.2);
63         lv[5] = (int)(cnt * 0.07);
64         lv[6] = (int)(cnt * 0.03);
65         lv[2] = cnt-lv[3]-lv[4]-lv[5]-lv[6];
66         for(int i=0, k=1; i<n; ++k)
67         {
68             for(int j=1; j<=lv[k]; ++j, ++i)
69             {
70                 man[i].degree = k;
71             }
72         }
73         sort(man, man+n, cmp2);
74         for(int i=0; i<n; ++i)
75         {
76             printf("LV%d\n", man[i].degree);
77         }
78     }
79     return 0;
80 }
View Code

 

E - Easy 2048

F - Calculate the Function

【题意】给你一个n个数的序列 Ai,定义一个[L,R]的查询,求Fi(R)的值。

 

  • Fi (Li) = ALi ;
  • Fi (Li + 1) = A(Li + 1);
  • for all x >= Li + 2Fi (x) = Fi (x – 1) + Fi (x – 2)  ×  Ax;

 

【思路】由上面的公式,对于每一个Ai可以构造出QQ截图20140513095147,则Fi(R)可以由下面的公式

QQ截图20140513095048

然后用线段树维护这个矩阵,查询就很快速了。下面是代码:

 

  1 /*
  2 ** ZOJ 3772 Calculate the Function
  3 ** Created by Rayn @@ 2014/05/13
  4 */
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <algorithm>
  8 #define MOD 1000000007
  9 using namespace std;
 10 typedef long long LL;
 11 const int MAXN = 100005;
 12 
 13 struct Martix
 14 {
 15     LL arr[2][2];
 16     Martix(int x11=0, int x12=0, int x21 =0, int x22=0)
 17     {
 18         arr[0][0] = x11; arr[0][1] = x12;
 19         arr[1][0] = x21; arr[1][1] = x22;
 20     }
 21     Martix operator * (const Martix& b) const
 22     {
 23         Martix res(0, 0, 0, 0);
 24         for(int i=0; i<2; ++i)
 25         {
 26             for(int j=0; j<2; ++j)
 27             {
 28                 for(int k=0; k<2; ++k)
 29                 {
 30                     res.arr[i][j] += arr[i][k] * b.arr[k][j];
 31                     res.arr[i][j] %= MOD;
 32                 }
 33             }
 34         }
 35         return res;
 36     }
 37 };
 38 struct SegmentTree
 39 {
 40     int l, r;
 41     Martix val;
 42 } tree[MAXN<<2];
 43 
 44 int A[MAXN];
 45 
 46 void BuildTree(int l, int r, int root)
 47 {
 48     tree[root].l = l;
 49     tree[root].r = r;
 50     if(l == r)
 51     {
 52         tree[root].val = Martix(1, 1, A[l], 0);
 53         return ;
 54     }
 55     int mid = (l + r) >> 1;
 56     BuildTree(l, mid, root<<1);
 57     BuildTree(mid+1, r, root<<1|1);
 58     tree[root].val = tree[root<<1].val * tree[root<<1|1].val;
 59 }
 60 Martix Query(int left, int right, int root)
 61 {
 62     if(left <= tree[root].l && tree[root].r <= right)
 63     {
 64         return tree[root].val;
 65     }
 66     Martix res(1, 0, 0, 1);
 67     int mid = (tree[root].l + tree[root].r) >> 1;
 68     if(left <= mid)
 69         res = res * Query(left, right, root<<1);
 70     if(right > mid)
 71         res = res * Query(left, right, root<<1|1);
 72     return res;
 73 }
 74 int main()
 75 {
 76     int T;
 77     scanf("%d", &T);
 78     while(T--)
 79     {
 80         int N, M;
 81         scanf("%d%d", &N, &M);
 82         for(int i=1; i<=N; ++i)
 83         {
 84             scanf("%d", &A[i]);
 85         }
 86         BuildTree(1, N, 1);
 87         while(M--)
 88         {
 89             int L, R;
 90             scanf("%d%d", &L, &R);
 91             if(R - L <= 1)
 92             {
 93                 printf("%d\n", A[R]);
 94             }
 95             else
 96             {
 97                 Martix res = Query(L+2, R, 1);
 98                 LL ans = (A[L+1]*res.arr[0][0] + A[L]*res.arr[1][0]) % MOD;
 99                 printf("%lld\n", ans);
100             }
101         }
102 
103     }
104     return 0;
105 }
View Code

 

G - Paint the Grid

H - Power of Fibonacci

I - ?(>_o)!

【题意】?(>_o)! 是一种简单的语言,给你一段源代码,然后判断输出是否和源代码相同。

【思路】这道题说了很多废话,其实就是就两个地方需要判断,对于输出,存在"_"会输出源代码,"!"会输出"Hello, world!"。然后就判断一下是否和源代码相同即可。代码如下:

 

 1 /*
 2 ** ZOJ 3775 ?(>_o)!
 3 ** Created by Rayn @@ 2014/05/10
 4 */
 5 #include <iostream>
 6 #include <cstdio>
 7 #include <string>
 8 #include <algorithm>
 9 using namespace std;
10 
11 bool Check(string& s)
12 {
13     string tmp = "";
14     for(int i=0; i<s.length(); ++i)
15     {
16         if(s[i] == '_')
17             tmp += s;
18         else if(s[i] == '!')
19             tmp += "Hello, world!";
20         if(tmp.length() > s.length())
21             return false;
22     }
23     return s == tmp;
24 }
25 int main()
26 {
27     int t;
28     string str;
29 
30     scanf("%d%*c", &t);
31     while(t--)
32     {
33         getline(cin, str);
34         if(Check(str))
35             puts("Yes");
36         else
37             puts("No");
38     }
39     return 0;
40 }
View Code

 

 

 

 

 

 

posted @ 2014-05-16 12:39  Rayn  阅读(186)  评论(0编辑  收藏  举报