ZOJ Monthly, July 2012 題解


既然官方沒有出題解,這里就說下比賽時候過的幾題的題解。

A - Magic Number  

討論下 1000/x 的情況就可以了。  

 

B - Battle Ships  

dp[i][j] 表示 傷了i血,當前傷害為j。 dp[i][j] = min(dp[i][j], dp[i-t[k]*(j-l[k])][j-l[k]] + t[k]);

當然最后不能只去找 dp[L][j] 。  不造戰艦的時間最后累加傷害到L。

B
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<climits>
 6 #include<cstdlib>
 7 #include<queue>
 8 using namespace std;
 9 #define N 710
10 #define inf 1000000000
11 typedef long long LL;
12 int t[N], l[N], dp[N][N];
13 int main() {
14     int n, len;
15     while (scanf("%d%d", &n, &len) != EOF) {
16         int Max = 700;
17         for (int i = 0; i < n; ++i) 
18             scanf("%d%d", &t[i], &l[i]);
19         for (int i = 0; i <= len; ++i) for (int j = 0; j <= Max; ++j)
20             dp[i][j] = inf;
21         dp[0][0] = 0;
22         for (int i = 0; i <= len; ++i) {
23             for (int j = 0; j <= Max; ++j) {
24                 for (int k = 0; k < n; ++k) {
25                     if (j >= l[k] && i >= t[k]*(j-l[k])) 
26                         dp[i][j] = min(dp[i][j], dp[i-t[k]*(j-l[k])][j-l[k]] + t[k]);
27                 }
28             }
29         }
30         int ans = inf;
31         for (int i = 0; i <= len; ++i) for (int j = 1; j <= Max; ++j) {
32             int temp = (len-i)/j;
33             if ((len-i) % j) temp ++;
34             ans = min(ans, temp + dp[i][j]);
35         }
36         printf("%d\n", ans);
37     }
38     return 0;
39 }

 

C,D可以推出公式,反正我是推不出來。這里給各種神牛跪了。

 

E - Treasure Hunt I

樹形背包,n很小, 偷懶的話 n^3 就可以過去

dp[u][j] = max(dp[u][j], dp[v][k]+dp[u][j-k-l*2]);  l是邊的值

 

F - Treasure Hunt II

每個大方向最多轉一次,每次按照大方向走,另一邊盡量貼近反方向,記錄區間金幣值sum[l, r] ,然后正反掃一次,統計最大的。

F
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<climits>
 6 #include<cstdlib>
 7 #include<queue>
 8 using namespace std;
 9 typedef long long LL;
10 #define N 100010
11 #define inf 1000000000
12 LL val[N], sum[N];
13 int id[N];
14 int n, p, m, t;
15 LL solve() {
16     memset(id, -1, sizeof(id));
17     id[p] = p;
18     LL ans = 0;
19     int s1, s2;
20     s1 = s2 = p;
21     for (int cs = 0; cs < t; ++cs) {
22         if (s1 != 1) s1--;
23         else break;
24         if (s2 != n && s2+1-s1 <= m) s2++;
25         else if (s2-s1 > m && s2 != 1) s2--;
26         id[s1] = s2;
27     }
28     for (int i = 1; i <= p; ++i) {
29         if (p-i > t || id[i] == -1) continue;
30         LL temp = sum[p]-sum[i-1];
31         int r = min(n, id[i]+t-(p-i));
32         if (r < p) continue;
33         ans = max(ans, temp + sum[r]-sum[p]);
34     }
35     return ans;
36 }
37 int main() {
38     while (scanf("%d%d", &n, &p) != EOF) {
39         sum[0] = 0;
40         for (int i = 1; i <= n; ++i) {
41             scanf("%lld", &val[i]);
42             sum[i] = sum[i-1] + val[i];
43         }
44         scanf("%d%d", &m, &t);
45         if (n == 1) {
46             printf("%lld\n", val[1]);
47             continue;
48         }
49         LL ans = solve();
50         for (int i = 1; i <= n/2; ++i)
51             swap(val[i], val[n-i+1]);
52         for (int i = 1; i <= n; ++i)
53             sum[i] = sum[i-1] + val[i];
54         p = n-p+1;
55         ans = max(ans, solve());
56         printf("%lld\n", ans);
57     }
58     return 0;
59 }

 

 G - Treasure Hunt III

麻煩的dp,題解在下一篇報告中,比賽沒出。

 

H - Treasure Hunt IV

看這么多人過只好找規律了...

然后,推出公式水過。

H
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<climits>
 6 #include<cstdlib>
 7 #include<queue>
 8 using namespace std;
 9 typedef long long LL;
10 #define N 210 
11 #define inf 1000000000
12 LL so(LL n) {
13     return n*(n+1)*4;
14 }
15 LL find(LL x) {
16     if (x == -1) return 0;
17     LL l = 0, r = 1518500249ll, t;
18     while (l <= r) {
19         LL mid = (l+r)/2;
20         if (so(mid)-1 < x) {
21             t = mid;
22             l = mid+1;
23         }
24         else r = mid-1;
25     }
26     x = x - so(t) + 1;
27     t++;
28     LL id = 2*t*t-t;
29     t *= 4;
30     if (x <= t) return id;
31     else return id + x - t;
32 }
33 int main() {
34     LL a, b;
35     while (scanf("%lld%lld", &a, &b) != EOF) {
36         printf("%lld\n", find(b)-find(a-1));
37     }
38     return 0;
39 }

 

I - Information

好殘暴的強連通,直接枚舉刪掉的點就行了 復雜度 n*m

 

J - Watashi's BG

把n個點平分成l, r兩堆點。

2^l 和 2^r 枚舉。排序后,一隊數據從小到大,一隊數據從大到小掃過去就可以了。

復雜度 2^15 * 15

J
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<climits>
 6 #include<cstdlib>
 7 #include<queue>
 8 using namespace std;
 9 #define N 710
10 #define inf 1000000000
11 typedef long long LL;
12 int val[N];
13 int qu[2][1<<16];
14 int main() {
15     int n, m;
16     while (scanf("%d%d", &n, &m) != EOF) {
17         for (int i = 0; i < n; ++i) 
18             scanf("%d", &val[i]);
19         int a = n/2;
20         int b = n-a;
21         int top1, top2;
22         top1 = top2 = 0;
23         for (int i = 0; i < 1<<a; ++i) {
24             int temp = i, k = 0, s = 0;
25             while (temp) {
26                 if (temp&1) s += val[k];
27                 temp >>= 1;
28                 k++;
29             }
30             qu[0][top1++] = s;
31         }
32         int ans = 0;
33         for (int i = 0; i < 1<<b; ++i) {
34             int temp = i, k = a, s = 0;
35             while (temp) {
36                 if (temp&1) s += val[k];
37                 temp >>= 1;
38                 k++;
39             }
40             qu[1][top2++] = s;
41         }
42         sort(qu[0], qu[0]+top1);
43         sort(qu[1], qu[1]+top2);
44         int j = top2-1;
45         for (int i = 0; i < top1; ++i) {
46             for ( ; j >= 0; --j) {
47                 if (qu[0][i] + qu[1][j] <= m) {
48                     ans = max(ans, qu[0][i] + qu[1][j]);
49                     break;
50                 }
51             }
52         }
53         printf("%d\n", ans);
54     }
55     return 0;
56 }

 

 

K - Watermelon Full of Water

dp[i] 處理完前i天的最小花費。

當然直接轉移會TLE,我是用線段樹優化的,把能轉移前K天到狀態添加進去, 查找是找I~N天的轉移狀態的最小值。

K
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<climits>
 6 #include<cstdlib>
 7 using namespace std;
 8 #define N 50010 
 9 #define inf 1000000000
10 typedef long long LL;
11 struct node {
12     int l, r;
13     LL num;
14 }tr[N*5];
15 LL val[N], dp[N];
16 int day[N];
17 void build(int L, int R, int x) {
18     tr[x].l = L;
19     tr[x].r = R;
20     tr[x].num = 1000000000000000ll;
21     if (L == R) return ;
22     int mid = L+R >> 1;
23     build(L, mid, x<<1);
24     build(mid+1, R, x<<1|1);
25 }
26 void add(int id, int x, LL v) {
27     if (tr[x].l == tr[x].r) {
28         tr[x].num = min(tr[x].num, v);
29         return ;
30     }
31     int mid = tr[x].l + tr[x].r >> 1;
32     if (mid >= id) add(id, x<<1, v);
33     else add(id, x<<1|1, v);
34     tr[x].num = min(tr[x<<1].num, tr[x<<1|1].num);
35 }
36 LL find(int L, int R, int x) {
37     if (tr[x].l >= L && tr[x].r <= R)
38         return tr[x].num;
39     int mid = tr[x].l + tr[x].r >> 1;
40     if (mid >= R) return find(L, R, x<<1);
41     else if (mid < L) return find(L, R, x<<1|1);
42     else return min(find(L, mid, x<<1), find(mid+1, R, x<<1|1));
43 }
44 int main() {
45     int n;
46     while (scanf("%d", &n) != EOF) {
47         for (int i = 1; i <= n; ++i) 
48             scanf("%lld", &val[i]);
49         for (int i = 1; i <= n; ++i)
50             scanf("%d", &day[i]);
51         build(1, n, 1);
52         for (int i = 1; i <= n; ++i) {
53             add(day[i]+i-1 > n ? n : day[i]+i-1, 1, dp[i-1]+val[i]);
54             dp[i] = find(i, n, 1);
55         }
56         printf("%lld\n", dp[n]);
57     }
58     return 0;
59 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM