【NOIP2015】反思+题解
D1T1> 神奇的幻方
模拟即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define rep(i, a, b) for (int i = a; i <= b; i++) 5 #define drep(i, a, b) for (int i = a; i >= b; i--) 6 #define REP(i, a, b) for (int i = a; i < b; i++) 7 #define pb push_back 8 #define mp make_pair 9 #define clr(x) memset(x, 0, sizeof(x)) 10 #define xx first 11 #define yy second 12 13 using namespace std; 14 15 typedef long long i64; 16 typedef pair<int, int> pii; 17 const int inf = ~0U >> 1; 18 const i64 INF = ~0ULL >> 1; 19 //****************************** 20 21 int map[55][55]; 22 int main() { 23 int n; 24 scanf("%d", &n); 25 pii last = mp(1, n / 2 + 1); 26 map[1][n / 2 + 1] = 1; 27 rep(i, 2, n * n) { 28 if (last.xx == 1 && last.yy != n) { 29 map[n][last.yy + 1] = i; 30 last = mp(n, last.yy + 1); 31 } 32 else if (last.yy == n && last.xx != 1) { 33 map[last.xx - 1][1] = i; 34 last = mp(last.xx - 1, 1); 35 } 36 else if (last.xx == 1 && last.yy == n) { 37 map[last.xx + 1][last.yy] = i; 38 last = mp(last.xx + 1, last.yy); 39 } 40 else if (last.xx != 1 && last.yy != n && !map[last.xx - 1][last.yy + 1]) { 41 map[last.xx - 1][last.yy + 1] = i; 42 last = mp(last.xx - 1, last.yy + 1); 43 } 44 else { 45 map[last.xx + 1][last.yy] = i; 46 last = mp(last.xx + 1, last.yy); 47 } 48 } 49 rep(i, 1, n) { 50 rep(j, 1, n) { 51 if (j != 1) printf(" "); 52 printf("%d", map[i][j]); 53 } 54 puts(""); 55 } 56 return 0; 57 }
D1T2> 信息传递
一个点只有一个出度 => 环不会交叉
1)dfs找环 2)tarjan找scc
考试的时候就直接写了tarjan...
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define rep(i, a, b) for (int i = a; i <= b; i++) 5 #define drep(i, a, b) for (int i = a; i >= b; i--) 6 #define REP(i, a, b) for (int i = a; i < b; i++) 7 #define pb push_back 8 #define mp make_pair 9 #define clr(x) memset(x, 0, sizeof(x)) 10 #define xx first 11 #define yy second 12 13 using namespace std; 14 15 typedef long long i64; 16 typedef pair<int, int> pii; 17 const int inf = ~0U >> 1; 18 const i64 INF = ~0ULL >> 1; 19 //****************************** 20 21 const int maxn = 200005; 22 23 struct Ed { 24 int u, v, nx; Ed() {} 25 Ed(int _u, int _v, int _nx) 26 :u(_u), v(_v), nx(_nx) {} 27 } a[maxn]; 28 int fst[maxn], cnt; 29 void addedge(int u, int v) { 30 a[++cnt] = Ed(u, v, fst[u]); 31 fst[u] = cnt; 32 } 33 34 int dfn[maxn], low[maxn], Index, vis[maxn]; 35 int stack[maxn], top; 36 int scc_cnt; 37 int belong[maxn], size[maxn]; 38 void tarjan(int u) { 39 dfn[u] = low[u] = ++Index; 40 vis[u] = 1; 41 stack[++top] = u; 42 for (int i = fst[u]; i; i = a[i].nx) { 43 int v = a[i].v; 44 if (!dfn[v]) { 45 tarjan(v); 46 low[u] = min(low[u], low[v]); 47 } 48 else if (vis[v]) { 49 low[u] = min(low[u], dfn[v]); 50 } 51 } 52 if (dfn[u] == low[u]) { 53 scc_cnt++; 54 while (stack[top] != u) { 55 belong[stack[top]] = scc_cnt; 56 vis[stack[top]] = 0; 57 size[scc_cnt]++; 58 top--; 59 } 60 belong[stack[top]] = scc_cnt; 61 vis[stack[top]] = 0; 62 size[scc_cnt]++; 63 top--; 64 } 65 } 66 67 int main() { 68 int n; 69 scanf("%d", &n); 70 rep(i, 1, n) { 71 int id; 72 scanf("%d", &id); 73 addedge(i, id); 74 } 75 76 rep(i, 1, n) { 77 if (!dfn[i]) tarjan(i); 78 } 79 80 int ans = 0x3f3f3f3f; 81 rep(i, 1, scc_cnt) if (size[i] != 1) ans = min(ans, size[i]); 82 83 printf("%d\n", ans); 84 return 0; 85 }
D1T3> 斗地主
搜索题,以前在contest hunter上见过,没有订正...
因为1 2 3 4 5不能顺, 1 1 1 2 2 2不能连出,可以在读入时将牌的编号重新分配,只需要将 A 调整到 K 后,2 和 A 断开即可。
考试的时候想把所有可行的方案预处理出来,压位压在一起,然后状压dp,这样是不可行的,因为方案数多了后时间复杂度会爆炸。
以下代码可以过NOIP官方数据,但是过不了UOJ的加强版题目,会WA,这篇代码的思路主要是在每次判断时,人为地把4张和3张出掉,强剪枝。
1 #include <bits/stdc++.h> 2 #define rep(i, a, b) for (register int i = a; i <= b; i++) 3 #define drep(i, a, b) for (register int i = a; i >= b; i--) 4 #define REP(i, a, b) for (int i = a; i < b; i++) 5 #define pb push_back 6 #define mp make_pair 7 #define clr(x) memset(x, 0, sizeof(x)) 8 #define xx first 9 #define yy second 10 11 using namespace std; 12 13 typedef long long i64; 14 typedef pair<int, int> pii; 15 const int inf = ~0U >> 1; 16 const i64 INF = ~0ULL >> 1; 17 //******************************** 18 19 const int maxn = 20; 20 21 inline int read() { 22 int l = 1, s = 0; 23 char ch = getchar(); 24 while (ch < '0' || ch > '9') { if (ch == '-') l = -1; ch = getchar(); } 25 while (ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + ch - '0'; ch = getchar(); } 26 return l * s; 27 } 28 29 int poker[maxn]; 30 31 int ans = inf; 32 33 void dfs(int); 34 35 void group(int base, int len, int dep) { 36 rep(st, 1, 13 - len) { 37 if (poker[st] < base) continue; 38 int end; 39 for (end = st; end <= 12; end++) if (poker[end] < base) break; 40 if (--end - st + 1 < len) continue; 41 drep(k, end, st + len - 1) { 42 rep(i, st, k) poker[i] -= base; 43 poker[0] -= (k - st + 1) * base; 44 dfs(dep + 1); 45 rep(i, st, k) poker[i] += base; 46 poker[0] += (k - st + 1) * base; 47 } 48 } 49 } 50 51 int n, tong[maxn]; 52 53 void dfs(int dep) { 54 if (dep > ans) return; 55 if (poker[0] == 0) return; 56 rep(i, 1, 16) tong[poker[i]]++; 57 int sum(0); 58 while (tong[4] > 0) { 59 sum++; 60 tong[4]--; 61 if (tong[1] >= 2) tong[1] -= 2; 62 else if (tong[2] >= 2) tong[2] -= 2; 63 } 64 while (tong[3] > 0) { 65 sum++; 66 tong[3]--; 67 if (tong[1] >= 1) tong[1] -= 1; 68 else if (tong[2] >= 1) tong[2] -= 1; 69 } 70 if (tong[1] >= 2 && poker[15] >= 1 && poker[16] >= 1) sum--; 71 if (sum + tong[1] + tong[2] + dep < ans) ans = sum + tong[1] + tong[2] + dep; 72 tong[1] = tong[2] = 0; 73 74 group(3, 2, dep); 75 group(2, 3, dep); 76 group(1, 5, dep); 77 } 78 79 int main() { 80 int T; 81 T = read(), n = read(); 82 while (T--) { 83 memset(poker, 0, sizeof(poker)); 84 rep(i, 1, n) { 85 int rb, id; 86 id = read(); rb = read(); 87 if (id >= 3 && id <= 13) poker[id - 2]++; 88 else if (id == 1) poker[12]++; 89 else if (id == 2) poker[14]++; 90 else if (id == 0 && poker[15] == 0) poker[15]++; 91 else poker[16]++; 92 } 93 poker[0] = n; 94 ans = inf; 95 dfs(0); 96 printf("%d\n", ans); 97 } 98 return 0; 99 }
这一篇代码依然可以过NOIP官方数据,但是在UOJ加强版上在第9个extra test上t了,不知道卡时是否可以。
这个思路考虑了 AAAA2222 在一次出完的情况, 还考虑了在4带2时可以破坏3个一样的牌的情况,分别写出来就好了。
1 #include <bits/stdc++.h> 2 #define rep(i, a, b) for (int i = a; i <= b; i++) 3 #define drep(i, a, b) for (int i = a; i >= b; i--) 4 #define REP(i, a, b) for (int i = a; i < b; i++) 5 #define pb push_back 6 #define mp make_pair 7 #define clr(x) memset(x, 0, sizeof(x)) 8 #define xx first 9 #define yy second 10 11 using namespace std; 12 13 typedef long long i64; 14 typedef pair<int, int> pii; 15 const int inf = ~0U >> 1; 16 const i64 INF = ~0ULL >> 1; 17 //******************************** 18 19 const int maxn = 20; 20 21 int poker[maxn]; 22 23 int ans = inf; 24 25 void dfs(int dep, int order) { 26 if (dep > ans) return; 27 if (dep + poker[0] < ans) ans = dep + poker[0]; 28 if (poker[0] == 0) return; 29 30 //AAABBBCCC 31 if (order <= 0) 32 rep(st, 1, 12) { 33 if (poker[st] < 3) continue; 34 int end; 35 for (end = st; end <= 12; end++) if (poker[end] < 3) break; 36 end--; if (end - st < 1) break; 37 rep(k, st + 1, end) { 38 rep(i, st, k) poker[i] -= 3; 39 poker[0] -= (k - st + 1) * 3; 40 dfs(dep + 1, 0); 41 rep(i, st, k) poker[i] += 3; 42 poker[0] += (k - st + 1) * 3; 43 } 44 } 45 46 //AABBCC 47 if (order <= 1) 48 rep(st, 1, 12) { 49 if (poker[st] < 2) continue; 50 int end; 51 for (end = st; end <= 12; end++) if (poker[end] < 2) break; 52 end--; if (end - st + 1 < 3) continue; 53 rep(k, st + 2, end) { 54 rep(i, st, k) poker[i] -= 2; 55 poker[0] -= (k - st + 1) * 2; 56 dfs(dep + 1, 1); 57 rep(i, st, k) poker[i] += 2; 58 poker[0] += (k - st + 1) * 2; 59 } 60 } 61 62 //ABCDE 63 if (order <= 2) 64 rep(st, 1, 12) { 65 if (poker[st] < 1) continue; 66 int end; 67 for (end = st; end <= 12; end++) if (poker[end] < 1) break; 68 end--; if (end - st + 1 < 5) continue; 69 rep(k, st + 4, end) { 70 rep(i, st, k) poker[i] -= 1; 71 poker[0] -= k - st + 1; 72 dfs(dep + 1, 2); 73 rep(i, st, k) poker[i] += 1; 74 poker[0] += k - st + 1; 75 } 76 } 77 78 //AAAABC 79 if (order <= 3) 80 rep(st, 1, 14) { 81 if (poker[st] < 4) continue; 82 rep(i, 1, 16) { 83 if (poker[i] < 1 || i == st) continue; 84 poker[i] -= 1; 85 rep(j, i, 16) { 86 if (poker[j] < 1 || j == st) continue; 87 poker[st] -= 4; poker[j] -= 1; 88 poker[0] -= 6; 89 dfs(dep + 1, 3); 90 poker[st] += 4; poker[j] += 1; 91 poker[0] += 6; 92 } 93 poker[i] += 1; 94 } 95 } 96 97 //AAAABBCC 98 if (order <= 4) 99 rep(st, 1, 14) { 100 if (poker[st] < 4) continue; 101 rep(i, 1, 14) { 102 if (poker[i] < 2 || i == st) continue; 103 poker[i] -= 2; 104 rep(j, i, 14) { 105 if (poker[j] < 2 || j == st) continue; 106 poker[st] -= 4, poker[j] -= 2; 107 poker[0] -= 8; 108 dfs(dep + 1, 4); 109 poker[st] += 4, poker[j] += 2; 110 poker[0] += 8; 111 } 112 poker[i] += 2; 113 } 114 } 115 116 //AAABB 117 if (order <= 5) 118 rep(st, 1, 14) { 119 if (poker[st] < 3) continue; 120 rep(i, 1, 14) { 121 if (poker[i] < 2 || i == st) continue; 122 poker[st] -= 3, poker[i] -= 2; 123 poker[0] -= 5; 124 dfs(dep + 1, 5); 125 poker[st] += 3, poker[i] += 2; 126 poker[0] += 5; 127 } 128 } 129 130 //AAAB 131 if (order <= 6) 132 rep(st, 1, 14) { 133 if (poker[st] < 3) continue; 134 rep(i, 1, 16) { 135 if (poker[i] < 1 || i == st) continue; 136 poker[st] -= 3, poker[i] -= 1; 137 poker[0] -= 4; 138 dfs(dep + 1, 6); 139 poker[st] += 3, poker[i] += 1; 140 poker[0] += 4; 141 } 142 } 143 144 //AAAA 145 if (order <= 7) 146 rep(st, 1, 14) { 147 if (poker[st] < 4) continue; 148 poker[st] -= 4, poker[0] -= 4; 149 dfs(dep + 1, 7); 150 poker[st] += 4, poker[0] += 4; 151 } 152 153 //AAA 154 if (order <= 8) 155 rep(st, 1, 14) { 156 if (poker[st] < 3) continue; 157 poker[st] -= 3, poker[0] -= 3; 158 dfs(dep + 1, 8); 159 poker[st] += 3, poker[0] += 3; 160 } 161 162 //AA 163 if (order <= 9) 164 rep(st, 1, 14) { 165 if (poker[st] < 2) continue; 166 poker[st] -= 2, poker[0] -= 2; 167 dfs(dep + 1, 9); 168 poker[st] += 2, poker[0] += 2; 169 } 170 171 //Joker 172 if (order <= 10) 173 if (poker[15] && poker[16]) { 174 poker[15] = poker[16] = 0; 175 poker[0] -= 2; 176 dfs(dep + 1, 10); 177 poker[15] = poker[16] = 1; 178 poker[0] += 2; 179 } 180 } 181 182 int main() { 183 int T, n; 184 scanf("%d%d", &T, &n); 185 while (T--) { 186 memset(poker, 0, sizeof(poker)); 187 rep(i, 1, n) { 188 int rb, id; 189 scanf("%d%d", &id, &rb); 190 if (id >= 3 && id <= 13) poker[id - 2]++; 191 else if (id == 1) poker[12]++; 192 else if (id == 2) poker[14]++; 193 else if (id == 0 && poker[15] == 0) poker[15]++; 194 else poker[16]++; 195 } 196 poker[0] = n; 197 ans = inf; 198 dfs(0, 0); 199 printf("%d\n", ans); 200 } 201 return 0; 202 }
D2T1> 跳石头
二分+贪心。
noi.openjudge.cn的原题,首先二分答案,在二分答案的情况下,扫一遍n个石头,如果这个石头与前一个石头的距离小于二分的答案,那么就把前一个石头取消。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define rep(i, a, b) for (int i = a; i <= b; i++) 5 #define drep(i, a, b) for (int i = a; i >= b; i--) 6 #define REP(i, a, b) for (int i = a; i < b; i++) 7 #define pb push_back 8 #define mp make_pair 9 #define clr(x) memset(x, 0, sizeof(x)) 10 #define xx first 11 #define yy second 12 13 using namespace std; 14 15 typedef long long i64; 16 typedef pair<int, int> pii; 17 const int inf = ~0U >> 1; 18 const i64 INF = ~0ULL >> 1; 19 //****************************** 20 21 int map[55][55]; 22 int main() { 23 int n; 24 scanf("%d", &n); 25 pii last = mp(1, n / 2 + 1); 26 map[1][n / 2 + 1] = 1; 27 rep(i, 2, n * n) { 28 if (last.xx == 1 && last.yy != n) { 29 map[n][last.yy + 1] = i; 30 last = mp(n, last.yy + 1); 31 } 32 else if (last.yy == n && last.xx != 1) { 33 map[last.xx - 1][1] = i; 34 last = mp(last.xx - 1, 1); 35 } 36 else if (last.xx == 1 && last.yy == n) { 37 map[last.xx + 1][last.yy] = i; 38 last = mp(last.xx + 1, last.yy); 39 } 40 else if (last.xx != 1 && last.yy != n && !map[last.xx - 1][last.yy + 1]) { 41 map[last.xx - 1][last.yy + 1] = i; 42 last = mp(last.xx - 1, last.yy + 1); 43 } 44 else { 45 map[last.xx + 1][last.yy] = i; 46 last = mp(last.xx + 1, last.yy); 47 } 48 } 49 rep(i, 1, n) { 50 rep(j, 1, n) { 51 if (j != 1) printf(" "); 52 printf("%d", map[i][j]); 53 } 54 puts(""); 55 } 56 return 0; 57 }
D2T2> 子串
dp。
用f[i][j][k][2]表示第一个字符串中的前i位,取出k段,按顺序组合,拼出第二个字符串前j位的方案数,最后一位若为1则表示第i位被考虑在内(被选取),为0则为不被选取。
那么当S[i] == T[j]时(S 为 第一个字符串,T 为 第二个字符串)
f[i][j][k][1] = f[i - 1][j - 1][k][1] + f[i - 1][j - 1][k - 1][0] + f[i - 1][j - 1][k - 1][1];
f[i][j][k][0] = f[i - 1][j][k][0];
否则 f[i][j][k][1] = 0, f[i][j][k][0] = f[i - 1][j][k][0] + f[i - 1][j][k][1];
解释:当前字符能否接下去(假若S[i] ==T[j])实则取决于第i - 1个字符是否选取。
1 #include <bits/stdc++.h> 2 #define rep(i, a, b) for (int i = a; i <= b; i++) 3 #define drep(i, a, b) for (int i = a; i >= b; i--) 4 #define REP(i, a, b) for (int i = a; i < b; i++) 5 #define pb push_back 6 #define mp make_pair 7 #define clr(x) memset(x, 0, sizeof(x)) 8 #define xx first 9 #define yy second 10 11 using namespace std; 12 13 typedef long long i64; 14 typedef pair<int, int> pii; 15 const int inf = ~0U >> 1; 16 const i64 INF = ~0ULL >> 1; 17 //******************************* 18 19 const int maxn = 1005, maxm = 205; 20 const int mod = 1000000007; 21 22 int read() { 23 int s = 0, l = 1; 24 char ch = getchar(); 25 while (ch < '0' || ch > '9') { if (ch == '-') l = -1; ch = getchar(); } 26 while (ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + ch - '0'; ch = getchar(); } 27 return l * s; 28 } 29 30 char str1[maxn], str2[maxm]; 31 i64 f[2][maxm][maxm][2]; 32 33 int main() { 34 int n, m, k; 35 n = read(), m = read(), k = read(); 36 scanf("%s%s", str1 + 1, str2 + 1); 37 f[0][0][0][0] = f[1][0][0][0] = 1; 38 int flag = 0; 39 rep(i, 1, n) { 40 flag ^= 1; 41 int up = min(i, m); 42 rep(j, 1, up) { 43 if (str1[i] == str2[j]) rep(kk, 1, j) { 44 f[flag][j][kk][0] = (f[1 ^ flag][j][kk][0] + f[1 ^ flag][j][kk][1]) % mod; 45 f[flag][j][kk][1] = (f[1 ^ flag][j - 1][kk][1] + f[1 ^ flag][j - 1][kk - 1][0] + f[1 ^ flag][j - 1][kk - 1][1]) % mod; 46 } 47 else rep(kk, 1, j) { 48 f[flag][j][kk][0] = (f[1 ^ flag][j][kk][0] + f[1 ^ flag][j][kk][1]) % mod; 49 f[flag][j][kk][1] = 0; 50 } 51 } 52 } 53 printf("%lld\n", (f[flag][m][k][0] + f[flag][m][k][1]) % mod); 54 return 0; 55 }
D2T3> 运输计划
两天内改完......
总结:考得挺扯蛋的,335,非常不满意:(
暴力分没有拿全,对算法的掌握不够深刻,最恶心的是做过的题也不会。
这TM混蛋的人生又干掉了我的希望,就这样吧,也没什么好说的...