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\n", ca++, (dfs(0, len - 1) + MOD) % MOD); 39 } 40 return 0; 41 }
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\n", ca++, ans % MOD * Invmod(24, MOD) % MOD); 49 } 50 return 0; 51 }
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\n", res[i]); 74 } 75 } 76 return 0; 77 }
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\n", ca++, dp[len]); 26 } 27 return 0; 28 }
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\n", ca++, ans); 109 } 110 return 0; 111 }
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 }