反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下。
upd:任务倒是完成了,我也自闭了。
CST2018 2-1 Meteorites:
乘法版的石子合并,堆 + 高精度。
写起来有点烦貌似。
upd:由于内存问题我高精度是动态开点,同时用的是可并堆(比较简单)。

1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 5 using namespace std; 6 typedef double lf; 7 typedef long long ll; 8 const lf pi = acos(-1.0); 9 const int N = 200005; 10 const int MaxLen = 2000005; 11 const int MOD = 10000; 12 13 struct BigNumber; 14 inline int getint(); 15 inline void getInt(BigNumber &res); // get Big number 16 inline void print(ll *num, int Len); 17 18 template<class T> inline void swap(T &x, T &y) { 19 register T tmp; 20 tmp = x, x = y, y = tmp; 21 } 22 23 int n; 24 25 struct Complex { 26 lf x, y; 27 28 Complex(lf _x = 0, lf _y = 0) : x(_x), y(_y) { 29 } 30 ~Complex() { 31 } 32 33 Complex operator +(const Complex &_c) { 34 return Complex(x + _c.x, y + _c.y); 35 } 36 Complex operator -(const Complex &_c) { 37 return Complex(x - _c.x, y - _c.y); 38 } 39 Complex operator *(const Complex &_c) { 40 return Complex(x * _c.x - y * _c.y, x * _c.y + y * _c.x); 41 } 42 Complex operator *(const lf &_x) { 43 return Complex(_x * x, _x * y); 44 } 45 Complex operator !() { 46 return Complex(x, -y); 47 } 48 } w[MaxLen], A[MaxLen], B[MaxLen], C[MaxLen]; 49 50 struct BigNumber { 51 ll *x; 52 int len; 53 54 BigNumber() { 55 x = new ll[1]; 56 x[0] = 0; 57 len = 0; 58 } 59 60 void destroy() { 61 if (x) delete[] x; 62 } 63 64 ~BigNumber() { 65 destroy(); 66 } 67 68 void ChangeSize(int length) { 69 if (x) delete[] x; 70 x = new ll[length + 1]; 71 memset(x, 0, (length + 1) * sizeof(x)); 72 len = 0; 73 } 74 75 void zero() { 76 ChangeSize(0); 77 x[0] = 0; 78 len = 0; 79 } 80 void one() { 81 ChangeSize(0); 82 x[0] = 1; 83 len = 0; 84 } 85 86 void copy(const BigNumber &_num) { 87 ChangeSize(_num.len); 88 len = _num.len; 89 for (int i = len; i >= 0; --i) 90 x[i] = _num.x[i]; 91 } 92 93 inline bool operator > (const BigNumber &_num) const { 94 if (len > _num.len) return 1; 95 if (len < _num.len) return 0; 96 for (int i = len; i >= 0; --i) { 97 if (x[i] > _num.x[i]) return 1; 98 if (x[i] < _num.x[i]) return 0; 99 } 100 return 1; 101 } 102 103 void print() { 104 for (int i = len; i >= 0; --i) 105 printf(i == len ? "%lld" : "%04lld", x[i]); 106 puts(""); 107 } 108 }; 109 110 struct heap { 111 heap *ls, *rs; 112 BigNumber num; 113 int dep; 114 115 void *operator new(size_t) { 116 static heap mempool[N << 2], *c = mempool; 117 c -> ls = c -> rs = NULL; 118 c -> dep = 1; 119 c -> num.zero(); 120 return c++; 121 } 122 123 inline void get_value(const BigNumber &_num) { 124 num.copy(_num); 125 } 126 127 #define Dep(p) (p ? p -> dep : 0) 128 inline void update() { 129 dep = Dep(rs) + 1; 130 } 131 132 friend heap* merge(heap *x, heap *y) { 133 if (!x) return y; 134 if (!y) return x; 135 if (x -> num > y -> num) swap(x, y); 136 x -> rs = merge(x -> rs, y); 137 if (Dep(x -> rs) > Dep(x -> ls)) 138 swap(x -> ls, x -> rs); 139 x -> update(); 140 return x; 141 } 142 #undef Dep 143 144 inline heap* pop() { 145 this -> num.ChangeSize(0); 146 return merge(ls, rs); 147 } 148 } *Root; 149 150 151 void work(const BigNumber &a, const BigNumber &b, BigNumber &c) { 152 int n = a.len, m = b.len, l = a.len + b.len + 4; 153 c.ChangeSize(l); 154 155 for (int k = 0; k <= l; ++k) c.x[k] = 0; 156 157 for (int i = 0; i <= n; ++i) 158 for (int j = 0; j <= m; ++j) 159 c.x[i + j] += a.x[i] * b.x[j]; 160 for (int k = 0; k < l; ++k) { 161 c.x[k + 1] += c.x[k] / MOD; 162 c.x[k] %= MOD; 163 } 164 165 while (c.x[l] == 0) --l; 166 c.len = l; 167 } 168 169 int main() { 170 BigNumber ans, tmp, a, b, c; 171 heap *tmp_node; 172 173 n = getint(); 174 tmp.one(); 175 176 Root = new()heap; 177 Root -> get_value(tmp); 178 179 for (int i = 1; i <= n; ++i) { 180 getInt(tmp); 181 tmp_node = new()heap; 182 tmp_node -> get_value(tmp); 183 184 Root = merge(Root, tmp_node); 185 } 186 187 188 ans.one(); 189 for (int i = 1; i <= n; ++i) { 190 a.copy(Root -> num); 191 Root = Root -> pop(); 192 b.copy(Root -> num); 193 Root = Root -> pop(); 194 /* 195 puts("a and b:"); 196 a.print(); 197 b.print(); 198 puts("---------"); 199 */ 200 work(a, b, c); 201 /* 202 puts("c:"); 203 c.print(); 204 */ 205 tmp.copy(ans); 206 if (i != 1) { 207 /* 208 puts("----"); 209 tmp.print(); 210 c.print(); 211 */ 212 work(tmp, c, ans); 213 } 214 /* 215 puts("ans:"); 216 ans.print(); 217 */ 218 tmp_node = new()heap; 219 tmp_node -> get_value(c); 220 221 Root = merge(Root, tmp_node); 222 } 223 ans.print(); 224 225 return 0; 226 } 227 228 const int BUF_SIZE = 30; 229 char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1; 230 #define isdigit(x) ('0' <= x && x <= '9') 231 #define PTR_NEXT() { 232 if (++buf_s == buf_t) 233 buf_s = buf, buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); 234 } 235 236 int getint() { 237 register int x = 0; 238 while (!isdigit(*buf_s)) PTR_NEXT(); 239 while (isdigit(*buf_s)) { 240 x = x * 10 + *buf_s - '0'; 241 PTR_NEXT(); 242 } 243 return x; 244 } 245 246 void getInt(BigNumber &res) { 247 static ll num[50]; 248 static int len, Len, cnt, base; 249 memset(num, 0, sizeof(num)), len = 0; 250 for (int i = 0; i < 50; ++i) num[i] = 0; 251 252 while (!isdigit(*buf_s)) PTR_NEXT(); 253 while (isdigit(*buf_s) && buf_s != buf_t) { 254 num[len++] = *buf_s - '0'; 255 PTR_NEXT(); 256 } 257 len -= 1; 258 259 res.ChangeSize((len + 4) / 4 - 1); 260 Len = -1, cnt = 0; 261 for (int i = len; i >= 0; --i) { 262 cnt++; 263 if (cnt % 4 == 1) Len += 1, base = 1; 264 res.x[Len] += base * num[i]; 265 base *= 10; 266 } 267 res.len = Len; 268 269 /* 270 for (int i = 0; i <= len; ++i) 271 printf("%lld ", num[i]); 272 puts(""); 273 274 res.print(); 275 */ 276 }
CST2018 2-2 Circuit
首先是一个二进制trie + 贪心,但是由于有间隔限制,所以这个trie要支持插入和删除标记操作。
写起来并不麻烦。
upd:哪个xx卡内存。。。要把指针改成数组下标,同时把叶子和非叶子分开。

1 #include <cstdio> 2 #include <cstring> 3 4 using namespace std; 5 typedef unsigned long long ull; 6 const int N = 5e5 + 5; 7 const int SIZE = 18e6 + 5; 8 int n, k; 9 int a[100]; 10 ull f[N]; 11 12 struct trie_node { 13 int son[2]; 14 int cnt; 15 } trie[SIZE]; 16 int Root; 17 int cnt = 0; 18 19 struct leaf_node { 20 int cnt; 21 int next; 22 } leaf[N]; 23 int cnt_leaf = 0; 24 25 26 int get_new() { 27 ++cnt; 28 trie[cnt].son[0] = trie[cnt].son[1] = -1; 29 trie[cnt].cnt = 0; 30 return cnt; 31 } 32 33 int get_new_leaf() { 34 ++cnt_leaf; 35 leaf[cnt_leaf].cnt = 0; 36 leaf[cnt_leaf].next = -1; 37 return cnt_leaf; 38 } 39 40 struct Queue { 41 int next, value; 42 } q[N]; 43 int size; 44 45 void init() { 46 Root = get_new(); 47 } 48 49 void trie_add(int *a, int id) { 50 int tmp = Root; 51 for (int i = 1; i <= 64; ++i) { 52 trie[tmp].cnt += 1; 53 if (trie[tmp].son[a[i]] == -1) { 54 if (i != 64) trie[tmp].son[a[i]] = get_new(); 55 else trie[tmp].son[a[i]] = get_new_leaf(); 56 } 57 tmp = trie[tmp].son[a[i]]; 58 } 59 60 //leaf 61 leaf[tmp].cnt += 1; 62 int t = leaf[tmp].next; 63 if (t == -1) { 64 size += 1; 65 leaf[tmp].next = size; 66 q[size].next = -1; 67 q[size].value = id; 68 } else { 69 while (q[t].next != -1) t = q[t].next; 70 size += 1; 71 q[t].next = size; 72 q[size].next = -1; 73 q[size].value = id; 74 } 75 } 76 77 void trie_delete(int *a) { 78 int tmp = Root; 79 for (int i = 1; i <= 64; ++i) { 80 trie[tmp].cnt -= 1; 81 tmp = trie[tmp].son[a[i]]; 82 } 83 84 //leaf 85 leaf[tmp].cnt -= 1; 86 leaf[tmp].next = q[leaf[tmp].next].next; 87 } 88 89 int trie_find(int *a, int id) { 90 int tmp = Root; 91 int t; 92 for (int i = 1; i <= 64; ++i) { 93 if (i != 64) { 94 t = trie[tmp].son[!a[i]]; 95 if (t != -1 && trie[t].cnt != 0) 96 tmp = trie[tmp].son[!a[i]]; 97 else 98 tmp = trie[tmp].son[a[i]]; 99 } else { 100 t = trie[tmp].son[!a[i]]; 101 if (t != -1 && leaf[t].cnt != 0) 102 tmp = trie[tmp].son[!a[i]]; 103 else 104 tmp = trie[tmp].son[a[i]]; 105 } 106 } 107 int x = leaf[tmp].next; 108 while (q[x].value == id) { 109 x = q[x].next; 110 } 111 return q[x].value; 112 } 113 114 //-------------------------------------------------------------------- 115 //-------------------------------------------------------------------- 116 117 void split(ull x) { 118 memset(a, 0, sizeof(a)); 119 for (int i = 64; x; x >>= 1, --i) { 120 a[i] = x % 2; 121 } 122 /* 123 for (int i = 1; i <= 64; ++i) 124 printf("%d", a[i]); 125 puts(""); 126 */ 127 } 128 129 void add_in_trie(int i) { 130 if (i < 0 || i > n) return; 131 //printf("Add : %d %llu ", i, f[i]); 132 split(f[i]); 133 trie_add(a, i); 134 } 135 136 void delete_in_trie(int i) { 137 if (i < 0 || i > n) return; 138 //printf("Delete : %d %llu ", i, f[i]); 139 split(f[i]); 140 trie_delete(a); 141 } 142 143 int get_ans(int i) { 144 //printf("Find : %d %llu ", i, f[i]); 145 split(f[i]); 146 return trie_find(a, i); 147 } 148 149 150 int main() { 151 ull x; 152 scanf("%d%d", &n, &k); 153 /* 154 for (int i = 1; i <= n; ++i) { 155 scanf("%llu", &x); 156 printf("%llu ", x); 157 f[i] = x; 158 split(x); 159 } 160 */ 161 162 int L, R, nowL, nowR; 163 nowL = 1, nowR = 0; 164 L = 1 - k - 1; 165 R = 1 + k + 1; 166 init(); 167 for (int i = 1; i <= n; ++i) { 168 //add in trie 169 while (nowR < R) { 170 nowR += 1; 171 scanf("%llu", &f[nowR]); 172 split(f[nowR]); 173 add_in_trie(nowR); 174 } 175 //delete in trie 176 while (nowL < L) { 177 delete_in_trie(nowL); 178 nowL += 1; 179 } 180 181 //printf("%d %d %d ", i, nowL, nowR); 182 printf("%d ", get_ans(i) - 1); 183 184 //change the segment 185 L += 1; 186 R += 1; 187 if (L > n) L = n; 188 if (R > n) R = n; 189 } 190 191 return 0; 192 }
CST2018 2-3-1 Mooney(basic)
求一个有向图的强连通分量个数,直接tarjan就好了。
写起来 = 抄板子。
upd:没写。
CST2018 2-3-2 Mooney
两个小问题:
第一个就是求最短路,Dijkstra。
第二个先按照前一道题tarjan求强连通分量,然后对DAG树形DP。
写起来有点麻烦。
upd:第一问我写了SLF优化的spfa,应该不卡,第二问要注意有的连通分量走不到T要删掉。

1 #include <cstdio> 2 3 using namespace std; 4 const int N = 5e5 + 5; 5 const int M = 12e5 + 5; 6 const int inf = 1e9; 7 8 9 int n, m; 10 int f[N]; 11 int tot, first[N]; 12 int TOT, FIRST[N]; 13 14 struct edge { 15 int next, to; 16 edge() {} 17 edge(int _n, int _t) : next(_n), to(_t) {} 18 } e[M], E[M]; 19 20 inline void add_edge(int x, int y) { 21 e[++tot] = edge(first[x], y), first[x] = tot; 22 } 23 24 int q[N], v[N], dis[N]; 25 void spfa(int S) { 26 int p, x, y, l, r; 27 28 for (x = 1; x <= n; ++x) 29 dis[x] = inf; 30 31 q[0] = S, dis[S] = (f[S] == 0), v[S] = 1; 32 for (l = r = 0; l != (r + 1) % N; ) { 33 p = q[l], ++l %= N; 34 for (x = first[p]; x; x = e[x].next) { 35 y = e[x].to; 36 if (dis[p] + (f[y] == 0) < dis[y]) { 37 dis[y] = dis[p] + (f[y] == 0); 38 if (!v[y]) { 39 v[y] = 1; 40 if (dis[y] < dis[q[l]]) q[(l += N - 1) %= N] = y; 41 else q[++r %= N] = y; 42 } 43 } 44 } 45 v[p] = 0; 46 } 47 } 48 49 int __main1__() { 50 spfa(1); 51 printf("%d ", dis[n]); 52 } 53 54 55 int low[N], dfn[N], vis[N], inq[N], s[N], w[N]; 56 int Cnt[N], num; 57 int VIS[N], ans[N]; 58 int cnt, top; 59 int S, T; 60 61 inline int min(int x, int y) { 62 return x < y ? x : y; 63 } 64 65 inline int max(int x, int y) { 66 return x > y ? x : y; 67 } 68 69 70 void dfs(int p){ 71 low[p] = dfn[p] = ++cnt; 72 vis[p] = inq[p] = 1; 73 s[++top] = p; 74 int x, y; 75 for (x = first[p]; x; x = e[x].next) 76 if (!vis[(y = e[x].to)]){ 77 dfs(y); 78 low[p] = min(low[p], low[y]); 79 }else 80 if (inq[y]) low[p] = min(low[p], dfn[y]); 81 if (low[p] == dfn[p]){ 82 ++num, y = 0; 83 while (y != p){ 84 inq[(y = s[top--])] = 0; 85 w[y] = num; 86 if (f[y] == 1) 87 ++Cnt[num]; 88 } 89 } 90 } 91 92 inline void ADD_EDGE(int x, int y) { 93 E[++TOT] = edge(FIRST[x], y), FIRST[x] = TOT; 94 } 95 96 void rebuild_graph() { 97 int x, y; 98 for (int i = 1; i <= n; ++i) 99 for (x = first[i]; x; x = e[x].next) 100 if (w[i] != w[(y = e[x].to)]) 101 ADD_EDGE(w[i], w[y]); 102 } 103 104 int tag[N]; 105 106 void work(int p) { 107 int x, y; 108 ans[p] = 0; 109 if (p == T) { 110 tag[p] = 1; 111 ans[p] = Cnt[T]; 112 return; 113 } 114 for (x = FIRST[p]; x; x = E[x].next) { 115 if (!VIS[y = E[x].to]) { 116 VIS[y] = 1; 117 work(y); 118 } 119 if (tag[y]) tag[p] = 1; 120 ans[p] = max(ans[p], ans[y]); 121 } 122 if (tag[p] == 1) 123 ans[p] += Cnt[p]; 124 } 125 126 int __main2__() { 127 for (int i = 1; i <= n; ++i) 128 if (!vis[i]) 129 dfs(i); 130 rebuild_graph(); 131 132 S = w[1]; 133 T = w[n]; 134 work(S); 135 136 printf("%d ", ans[S]); 137 } 138 139 int main() { 140 int x, y; 141 char ch; 142 143 scanf("%d%d ", &n, &m); 144 for (int i = 1; i <= n; ++i) { 145 ch = getchar(); 146 while (ch != 'm' && ch != 'M') 147 ch = getchar(); 148 if (ch == 'M') f[i] = 0; 149 if (ch == 'm') f[i] = 1; 150 } 151 152 for (int i = 1; i <= m; ++i) { 153 scanf("%d %d", &x, &y); 154 add_edge(x + 1, y + 1); 155 } 156 157 __main1__(); 158 __main2__(); 159 160 return 0; 161 }
CST2018 2-4 Sort
我记得好像是原题,忘了咋做了。
大概想法是归并排序的时候分析归并子序列1的前两个数和子序列2的前一个数的大小,不能证明其上界。。。
写起来不麻烦。。就是不知道对不对。
upd:自闭了,四路归并写不来。
CST2018 2-5 ChromPoly
也没有什么想法,直接dfs好像就可以了。
问题是怎么判断两张图是同构的,这样子可以大幅度剪枝,甚至在小情况的时候进行打表预处理。
然后这是个NP问题,我xxxx。
我还是决定用hash来做。。但是还是没想好怎么hash
写起来不麻烦,如果hash搞定了的话。
upd:并不是hash,有别人的代码,戳这里。写到一半自闭了,不想写了。
CST2018 2-6 Temperature
二维数组,单点修改,矩阵求和,在线算法。
好像可以写二维的树状数组,子矩阵可以通过左上角二维前缀和解决。
写起来比较简单。
upd:好像没什么好讲的,要是每道题都这么简单就好了。

1 #include <cstdlib> 2 #include "temperature.h" 3 4 using namespace std; 5 const int N = 1205; 6 const int M = 1205; 7 8 int sum[N][M]; 9 int _t[N][M]; 10 11 void change(int, int, int); 12 13 void init(int n, int m, int **temp) { 14 for (int i = 1; i <= n; ++i) 15 for (int j = 1; j <= m; ++j) { 16 change(i, j, temp[i][j]); 17 _t[i][j] = temp[i][j]; 18 } 19 } 20 21 inline int Q(int x, int y) { 22 int res = 0; 23 for (int i = x; i; i -= i&(-i)) 24 for (int j = y; j; j -= j&(-j)) 25 res += sum[i][j]; 26 return res; 27 } 28 29 int query(int x1, int y1, int x2, int y2) { 30 return (Q(x2, y2) - Q(x2, y1 - 1) - Q(x1 - 1, y2) + Q(x1 - 1, y1 - 1)) / ((x2 - x1 + 1) * (y2 - y1 + 1)); 31 } 32 33 void change(int x, int y, int temp) { 34 int del = temp - _t[x][y]; 35 _t[x][y] = temp; 36 for (int i = x; i < N; i += i&(-i)) 37 for (int j = y; j < M; j += j&(-j)) 38 sum[i][j] += del; 39 }
CST2018 2-7 Virus
就是求所有离0最远的1,直接bfs就好了。
写起来非常简单。
upd: 好像也没什么好讲的,但是少了5分。。。有毒。

1 #include <cstdio> 2 3 using namespace std; 4 const int N = 1005; 5 const int M = 1005; 6 const int CNT = N * M; 7 8 const int dx[] = {1, -1, 0, 0}; 9 const int dy[] = {0, 0, 1, -1}; 10 11 int ans; 12 int n, m; 13 int w[N][M]; 14 int x[CNT], y[CNT]; 15 int time[CNT], vis[CNT]; 16 int q[CNT], l, r; 17 int cnt, cnt_virus; 18 19 20 inline void _max(int &x, int y) { 21 if (x < y) x = y; 22 } 23 24 inline void push_q(int x, int y, int t) { 25 r++; 26 q[r] = w[x][y]; 27 vis[w[x][y]] = 1; 28 time[w[x][y]] = t; 29 ans += t; 30 ++cnt_virus; 31 } 32 33 inline bool IN(int x, int y) { 34 return 0 < x && x <= n && 0 < y && y <= m; 35 } 36 37 int main() { 38 char ch; 39 int C; 40 int _x, _y, __x, __y; 41 scanf("%d%d", &n, &m); 42 cnt = 0; 43 l = 1, r = 0; 44 for (int i = 1; i <= n; ++i) 45 for (int j = 1; j <= m; ++j) { 46 w[i][j] = ++cnt; 47 x[cnt] = i, y[cnt] = j; 48 49 ch = getchar(); 50 while (ch != '0' && ch != '1') ch = getchar(); 51 if (ch == '0') push_q(i, j, 0); 52 } 53 while (l <= r) { 54 C = q[l]; 55 _x = x[C], _y = y[C]; 56 for (int i = 0; i < 4; ++i) { 57 __x = _x + dx[i], __y = _y + dy[i]; 58 if (IN(__x, __y) && !vis[w[__x][__y]]) 59 push_q(__x, __y, time[w[_x][_y]] + 1); 60 } 61 ++l; 62 } 63 printf("%d ", ans); 64 return 0; 65 }
CST2018 2-8 MST
求最小生成树。
ctrl c + ctrl v = AC。
20分题:1,2,3-2,4, 5, 6。
15分题:3-1, 7, 8。
吐槽:15分题和20分题真的是一个难度的吗?助教nb。