【 2013 Multi-University Training Contest 4 】

HDU 4632 Palindrome subsequence

dp[x][y]表示区间[x,y]构成回文串的方案数。

若str[x]==str[y],dp[x][y]=dp[x+1][y]+dp[x][y-1]-dp[x+1][y-1]+(dp[x+1][y-1]+1)=dp[x+1][y]+dp[x][y-1]+1。

若str[x]!=str[y],dp[x][y]=dp[x+1][y]+dp[x][y-1]-dp[x+1][y-1]。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 1010
 4 #define MOD 10007
 5 char str[MAXN];
 6 int dp[MAXN][MAXN];
 7 int dfs(int x, int y) {
 8     if (dp[x][y] == -1) {
 9         if (str[x] != str[y]) {
10             dp[x][y] = dfs(x + 1, y) + dfs(x, y - 1) - dfs(x + 1, y - 1);
11         } else {
12             dp[x][y] = dfs(x + 1, y) + dfs(x, y - 1) + 1;
13         }
14     }
15     dp[x][y] %= MOD;
16     return dp[x][y];
17 }
18 int main() {
19     int T;
20     int ca = 1;
21     int len;
22     int i;
23     scanf("%d", &T);
24     while (T--) {
25         memset(dp, -1, sizeof(dp));
26         scanf(" %s", str);
27         len = strlen(str);
28         for (i = 0; i < len; i++) {
29             dp[i][i] = 1;
30         }
31         for (i = 1; i < len; i++) {
32             if (str[i] == str[i - 1]) {
33                 dp[i - 1][i] = 3;
34             } else {
35                 dp[i - 1][i] = 2;
36             }
37         }
38         printf("Case %d: %d
", ca++, (dfs(0, len - 1) + MOD) % MOD);
39     }
40     return 0;
41 }
View Code

HDU 4633 Who's Aunt Zhang

由Polya得到:

本身到本身的置换有1种,k8+12+54

沿着一个面的中心旋转90度有3种,k(1+1+3)*(1+1+3)+1+9

沿着一个面的中心旋转270度有3种,k(1+1+3)*(1+1+3)+1+9

沿着一个面的中心旋转180度有3种,k(2+2+5)*(2+2+5)+2+18

沿着正方体的两个对顶点旋转120度有4种,k2+2+9+9+2+2

沿着正方体的两个对顶点旋转240度有4种,k2+2+9+9+2+2

沿着正方体的中心,与正方体任意两条对边的中点旋转180度有6种,k4+8+18+8

 1 #include<cstdio>
 2 #define MOD 10007
 3 int powmod(int a, int b) {
 4     int ans;
 5     for (ans = 1; b; b >>= 1) {
 6         if (b & 1) {
 7             ans *= a;
 8             ans %= MOD;
 9         }
10         a *= a;
11         a %= MOD;
12     }
13     return ans;
14 }
15 int ext_gcd(int a, int b, int &x, int &y) {
16     int t, d;
17     if (b == 0) {
18         x = 1;
19         y = 0;
20         return a;
21     }
22     d = ext_gcd(b, a % b, x, y);
23     t = x;
24     x = y;
25     y = t - a / b * y;
26     return d;
27 }
28 
29 int Invmod(int a, int n) {
30     int x, y;
31     if (ext_gcd(a, n, x, y) != 1)
32         return -1;
33     return (x % n + n) % n;
34 }
35 int main() {
36     int T;
37     int ca = 1;
38     int n;
39     int ans;
40     scanf("%d", &T);
41     while (T--) {
42         scanf("%d", &n);
43         ans = powmod(n, 8 + 12 + 54);
44         ans += 6 * powmod(n, 20);
45         ans += 3 * powmod(n, 38);
46         ans += 8 * powmod(n, 26);
47         ans += 6 * powmod(n, 38);
48         printf("Case %d: %d
", ca++, ans % MOD * Invmod(24, MOD) % MOD);
49     }
50     return 0;
51 }
View Code

HDU 4638 Group 

询问区间最少可以组成多少段,连续的数可以组成一段。

若x+1与x-1已经出现了,则加入x使得段数-1。

若x+1与x-1都没有出现,则加入x使得段数+1。

其他情况段数不变。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MAXN 100010
 5 using namespace std;
 6 int n, m;
 7 bool vis[MAXN];
 8 int arr[MAXN];
 9 int tree[MAXN];
10 int res[MAXN];
11 int pos[MAXN];
12 struct Ask {
13     int x, y;
14     int idx;
15     friend bool operator<(Ask a, Ask b) {
16         return a.x < b.x;
17     }
18 } ask[MAXN];
19 inline int lowbit(int x) {
20     return x & -x;
21 }
22 void update(int x, int val) {
23     for (; x < MAXN; x += lowbit(x)) {
24         tree[x] += val;
25     }
26 }
27 int sum(int x) {
28     int ans;
29     for (ans = 0; x > 0; x -= lowbit(x)) {
30         ans += tree[x];
31     }
32     return ans;
33 }
34 int main() {
35     int T;
36     int i, j;
37     scanf("%d", &T);
38     while (T--) {
39         scanf("%d%d", &n, &m);
40         for (i = 1; i <= n; i++) {
41             scanf("%d", &arr[i]);
42             pos[arr[i]] = i;
43         }
44         for (i = 0; i < m; i++) {
45             scanf("%d%d", &ask[i].x, &ask[i].y);
46             ask[i].idx = i;
47         }
48         sort(ask, ask + m);
49         memset(tree, 0, sizeof(tree));
50         memset(vis, false, sizeof(vis));
51         for (i = 1; i <= n; i++) {
52             vis[arr[i]] = true;
53             if (vis[arr[i] - 1] && vis[arr[i] + 1]) {
54                 update(i, -1);
55             }
56             if (!vis[arr[i] - 1] && !vis[arr[i] + 1]) {
57                 update(i, 1);
58             }
59         }
60         for (i = 0, j = 1; i < m; i++) {
61             for (; j < ask[i].x; j++) {
62                 if (vis[arr[j] + 1]) {
63                     update(pos[arr[j] + 1], 1);
64                 }
65                 if (vis[arr[j] - 1]) {
66                     update(pos[arr[j] - 1], 1);
67                 }
68                 vis[arr[j]] = false;
69             }
70             res[ask[i].idx] = sum(ask[i].y) - sum(ask[i].x - 1);
71         }
72         for (i = 0; i < m; i++) {
73             printf("%d
", res[i]);
74         }
75     }
76     return 0;
77 }
View Code

HDU 4639 Hehe

dp[i]表示以i结尾的方案数。

dp[i]=dp[i-1]。

若替换“hehe”,dp[i]+=dp[i-4]。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 100010
 4 #define MOD 10007
 5 int dp[MAXN];
 6 char str[MAXN];
 7 int main() {
 8     int T;
 9     int ca = 1;
10     int len;
11     int i;
12     scanf("%d", &T);
13     while (T--) {
14         scanf(" %s", str + 1);
15         len = strlen(str + 1);
16         dp[0] = 1;
17         for (i = 1; i <= len; i++) {
18             dp[i] = dp[i - 1];
19             if (i > 3 && str[i - 3] == 'h' && str[i - 2] == 'e'
20                     && str[i - 1] == 'h' && str[i] == 'e') {
21                 dp[i] += dp[i - 3];
22             }
23             dp[i] %= MOD;
24         }
25         printf("Case %d: %d
", ca++, dp[len]);
26     }
27     return 0;
28 }
View Code

 

4640 Island and study-sister

dp[i][j]表示访问了的地点压缩成i,最后访问的是j,它的最小花费。

f[i][j]表示i个人,共同访问的地点压缩成j,它的最小花费。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<queue>
  5 #define MAXN 17
  6 #define MAXM 3
  7 #define oo 987654321
  8 using namespace std;
  9 int g[MAXN + 1][MAXN + 1];
 10 int dis[MAXN + 1][MAXN + 1];
 11 int dp[1 << MAXN][MAXN];
 12 int f[MAXM + 1][1 << MAXN];
 13 vector<int> island;
 14 void floyd(int n) {
 15     for (int k = 0; k < n; k++) {
 16         for (int i = 0; i < n; i++) {
 17             for (int j = 0; j < n; j++) {
 18                 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
 19             }
 20         }
 21     }
 22 }
 23 bool getHelp() {
 24     for (int i = 0; i < (int) island.size(); i++) {
 25         if (dis[1][island[i]] >= oo) {
 26             return false;
 27         }
 28     }
 29     return true;
 30 }
 31 queue<pair<int, int> > q;
 32 int main() {
 33     int T;
 34     int ca = 1;
 35     int n, m, p;
 36     int x, y, val;
 37     int i, j, k;
 38     int vis;
 39     int ans;
 40     pair<int, int> head, tmp;
 41     scanf("%d", &T);
 42     while (T--) {
 43         scanf("%d%d", &n, &m);
 44         memset(g, 0x3f, sizeof(g));
 45         memset(dis, 0x3f, sizeof(dis));
 46         for (i = 0; i < m; i++) {
 47             scanf("%d%d%d", &x, &y, &val);
 48             x--;
 49             y--;
 50             g[x][y] = min(g[x][y], val);
 51             dis[x][y] = dis[y][x] = g[y][x] = g[x][y];
 52         }
 53         island.clear();
 54         scanf("%d", &p);
 55         for (i = 0; i < p; i++) {
 56             scanf("%d", &x);
 57             x--;
 58             island.push_back(x);
 59         }
 60         floyd(n);
 61         if (getHelp()) {
 62             memset(dp, 0x3f, sizeof(dp));
 63             dp[1][0] = 0;
 64             q.push(make_pair(1, 0));
 65             while (!q.empty()) {
 66                 head = q.front();
 67                 q.pop();
 68                 for (i = 0; i < n; i++) {
 69                     tmp.first = head.first | (1 << i);
 70                     tmp.second = i;
 71                     if (dp[tmp.first][tmp.second]
 72                             > dp[head.first][head.second]
 73                                     + g[head.second][tmp.second]) {
 74                         dp[tmp.first][tmp.second] = dp[head.first][head.second]
 75                                 + g[head.second][tmp.second];
 76                         q.push(tmp);
 77                     }
 78                 }
 79             }
 80             memset(f, 0x3f, sizeof(f));
 81             f[1][0] = 0;
 82             for (i = 1; i < (1 << n); i += 2) {
 83                 for (j = 0; j < n; j++) {
 84                     f[1][i] = min(f[1][i], dp[i][j]);
 85                 }
 86             }
 87             for (i = 2; i <= MAXM; i++) {
 88                 for (j = 1; j < (1 << n); j += 2) {
 89                     for (k = j; k >= 0; k = k ? (k - 1) & j : -1) {
 90                         f[i][j] = min(f[i][j],
 91                                 max(f[i - 1][k | 1], f[1][(j ^ k) | 1]));
 92                     }
 93                 }
 94             }
 95             vis = 0;
 96             for (i = 0; i < (int) island.size(); i++) {
 97                 vis |= 1 << island[i];
 98             }
 99             ans = oo;
100             for (i = 0; i < (1 << n); i++) {
101                 if ((i & vis) == vis) {
102                     ans = min(ans, f[3][i]);
103                 }
104             }
105         } else {
106             ans = -1;
107         }
108         printf("Case %d: %d
", ca++, ans);
109     }
110     return 0;
111 }
View Code

HDU 4642 Fliping game

若右下角的数为1,则Alice必胜。Alice先把右下角变为0,无论Bob如何操作右下角的数都会变为1。

若右下角的数为0,则Alice必败。Alice会把右下角的数变为1。

 1 #include<cstdio>
 2 int main() {
 3     int T;
 4     int n, m;
 5     int i, j, k;
 6     scanf("%d", &T);
 7     while (T--) {
 8         scanf("%d%d", &n, &m);
 9         for (i = 0; i < n; i++) {
10             for (j = 0; j < m; j++) {
11                 scanf("%d", &k);
12             }
13         }
14         if (k) {
15             puts("Alice");
16         } else {
17             puts("Bob");
18         }
19     }
20     return 0;
21 }
View Code
原文地址:https://www.cnblogs.com/DrunBee/p/3231379.html