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