【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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

  这一篇代码依然可以过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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

D2T3> 运输计划

  两天内改完......

 

总结:考得挺扯蛋的,335,非常不满意:(

  暴力分没有拿全,对算法的掌握不够深刻,最恶心的是做过的题也不会。

  这TM混蛋的人生又干掉了我的希望,就这样吧,也没什么好说的...

posted @ 2015-11-18 00:54  y7070  阅读(493)  评论(0编辑  收藏  举报