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 }

你可能感兴趣的:(2012)