2016 Multi-University Training Contest 1
分类:
IT文章
•
2025-02-04 12:32:38
1001 Abandoned country
先做最小生成树(边权不同保证唯一)。
然后打牌一下sz,单边贡献为边权乘两头sz积。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <vector>
5 #include <algorithm>
6 using namespace std;
7 typedef long long LL;
8 const int maxn = 1e5 + 10;
9 int n, m;
10 LL ans;
11
12
13 // G
14 struct Edge
15 {
16 int from, to, val;
17 Edge(int F, int T, int V): from(F), to(T), val(V){}
18 friend bool operator < (Edge A, Edge B)
19 {
20 return A.val < B.val;
21 }
22 };
23 vector<Edge> vec;
24
25
26 // UF
27 int fa[maxn];
28 int Find(int x)
29 {
30 return fa[x] == x ? x : fa[x] = Find(fa[x]);
31 }
32 void Union(int x, int y)
33 {
34 x = Find(x);
35 y = Find(y);
36 fa[y] = x;
37 }
38
39
40 // tree
41 int cnt, h[maxn];
42 struct edge
43 {
44 int to, pre, val;
45 } e[maxn<<1];
46 void add(int from, int to, int val)
47 {
48 cnt++;
49 e[cnt].pre = h[from];
50 e[cnt].to = to;
51 e[cnt].val = val;
52 h[from] = cnt;
53 }
54
55
56 // Kruskal
57 LL Kruskal()
58 {
59 LL ret = 0LL;
60 sort(vec.begin(), vec.end());
61 int sz = vec.size();
62 for(int i = 0; i < sz; i++)
63 {
64 Edge tmp = vec[i];
65 int a = tmp.from, b = tmp.to, v = tmp.val;
66 if(Find(a) == Find(b)) continue;
67 add(a, b, v), add(b, a, v);
68 Union(a, b);
69 ret = ret + v;
70 }
71 return ret;
72 }
73
74
75 // dp
76 int sz[maxn];
77 void dfs(int x, int f)
78 {
79 sz[x] = 1;
80 for(int i = h[x]; i; i = e[i].pre)
81 {
82 int to = e[i].to, v = e[i].val;
83 if(to == f) continue;
84 dfs(to, x);
85 sz[x] += sz[to];
86 ans += (LL) v * sz[to] * (n - sz[to]);
87 }
88 }
89
90
91 void init()
92 {
93 ans = 0LL;
94 cnt = 0;
95 vec.clear();
96 memset(h, 0, sizeof(h));
97 for(int i = 0; i < maxn; i++) fa[i] = i;
98 }
99
100
101 int main(void)
102 {
103 int T;
104 scanf("%d", &T);
105 while(T--)
106 {
107 init();
108 scanf("%d %d", &n, &m);
109 for(int i = 1; i <= m; i++)
110 {
111 int a, b, v;
112 scanf("%d %d %d", &a, &b, &v);
113 vec.push_back(Edge(a, b, v));
114 }
115 LL ans1 = Kruskal();
116 dfs(1, 0);
117 printf("%I64d %.2f
", ans1, 2.0 * ans / n / (n - 1));
118 }
119 return 0;
120 }
Aguin
1002 Chess
单行2^20局面暴力打好sg,每行^一下。
1 #include <iostream>
2 #include <cstdio>
3 using namespace std;
4 int sg[1<<20];
5
6 void cal(int x)
7 {
8 int last = -1, vis[20] = {0};
9 for(int i = 0; i < 20; i++)
10 {
11 if(!(x & (1 << i))) last = i;
12 else if(last != -1) vis[sg[((1<<last)|(1<<i))^x]] = 1;
13 }
14 for(int i = 0; i <= 20; i++)
15 if(!vis[i]) {sg[x] = i; return;}
16 }
17
18 int main(void)
19 {
20 for(int i = 0; i < (1 << 20); i++) cal(i);
21
22 int T;
23 scanf("%d", &T);
24 while(T--)
25 {
26 int N, ans = 0;
27 scanf("%d", &N);
28 for(int i = 1; i <= N; i++)
29 {
30 int m, x = 0;
31 scanf("%d", &m);
32 for(int i = 0; i < m; i++)
33 {
34 int y;
35 scanf("%d", &y);
36 x += 1 << (20 - y);
37 }
38 ans ^= sg[x];
39 }
40 puts(ans ? "YES" : "NO");
41 }
42 return 0;
43 }
Aguin
1003 Game
1004 GCD
打好st表,对每个固定的左端点,gcd最多只有logai个下降点。
可以二分每个下降点的位置,更好的方法是从右往左枚举左端点,维护下降点序列。
1 #include <iostream>
2 #include <cstdio>
3 #include <map>
4 #include <set>
5 using namespace std;
6 typedef long long LL;
7 const int maxn = 1e5 + 10;
8 map<LL, LL> M;
9 set<int> S;
10 set<int> :: iterator it;
11 int N;
12
13 LL gcd(LL a, LL b)
14 {
15 return a % b ? gcd(b, a % b) : b;
16 }
17
18 // RMQ
19 LL a[maxn], rmq[maxn][20];
20 void RMQ_init()
21 {
22 for(int i = 1; i <= N; i++) rmq[i][0] = a[i];
23 for(int j = 1; (1 << j) <= N; j++)
24 for(int i = 1; i + ( 1 << j ) - 1 <= N; i++)
25 rmq[i][j] = gcd(rmq[i][j-1] , rmq[i+(1<<j-1)][j-1]);
26 }
27 int RMQ_query(int l, int r)
28 {
29 int k = 0;
30 while( ( 1 << (k + 1) ) <= r - l + 1 ) k++;
31 return gcd(rmq[l][k], rmq[r-(1<<k)+1][k]);
32 }
33
34 int main(void)
35 {
36 int T;
37 scanf("%d", &T);
38 for(int kase = 1; kase <= T; kase++)
39 {
40 scanf("%d", &N);
41 for(int i = 1; i <= N; i++) scanf("%I64d", a + i);
42 RMQ_init();
43
44 S.clear(), M.clear();
45 for(int l = N; l; l--)
46 {
47 int last = N;
48 LL now = RMQ_query(l, N);
49 for(it = S.begin(); it != S.end();)
50 {
51 LL tmp = RMQ_query(l, -(*it));
52 if(tmp == now) S.erase(it++);
53 else
54 {
55 M[now] += (LL) (last + *it);
56 now = tmp;
57 last = -(*(it++));
58 }
59 }
60 M[now] += (LL) (last - l);
61 M[a[l]]++;
62 if(a[l] != now) S.insert(-l);
63 }
64
65 int Q;
66 scanf("%d", &Q);
67 printf("Case #%d:
", kase);
68 for(int i = 0; i < Q; i++)
69 {
70 int l, r;
71 scanf("%d %d", &l, &r);
72 LL ans = RMQ_query(l, r);
73 printf("%I64d %I64d
", ans, M[ans]);
74 }
75
76 }
77 return 0;
78 }
Aguin
1005 Necklace
枚举yin排列,以yang和空位建二分图。
空位两边yin不会使yang褪色则连边,N - 最大匹配即为答案。
习惯用Dinic跑,结果1s+。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <queue>
6 using namespace std;
7 const int INF = 1e9;
8 int lv[22], it[22];
9 int cnt, h[22];
10
11 struct edge
12 {
13 int to, pre, cap;
14 } e[1111];
15
16 void init()
17 {
18 memset(h, -1, sizeof(h));
19 cnt = 0;
20 }
21
22 void add(int from, int to, int cap)
23 {
24 e[cnt].pre = h[from];
25 e[cnt].to = to;
26 e[cnt].cap = cap;
27 h[from] = cnt;
28 cnt++;
29 }
30
31 void ad(int from, int to, int cap)
32 {
33 add(from, to, cap);
34 add(to, from, 0);
35 }
36
37 void bfs(int s)
38 {
39 memset(lv, -1, sizeof(lv));
40 queue<int> q;
41 lv[s] = 0;
42 q.push(s);
43 while(!q.empty())
44 {
45 int v = q.front(); q.pop();
46 for(int i = h[v]; i >= 0; i = e[i].pre)
47 {
48 int cap = e[i].cap, to = e[i].to;
49 if(cap > 0 && lv[to] < 0)
50 {
51 lv[to] = lv[v] + 1;
52 q.push(to);
53 }
54 }
55 }
56 }
57
58 int dfs(int v, int t, int f)
59 {
60 if(v == t) return f;
61 for(int &i = it[v]; i >= 0; i = e[i].pre)
62 {
63 int &cap = e[i].cap, to = e[i].to;
64 if(cap > 0 && lv[v] < lv[to])
65 {
66 int d = dfs(to, t, min(f, cap));
67 if(d > 0)
68 {
69 cap -= d;
70 e[i^1].cap += d;
71 return d;
72 }
73 }
74 }
75 return 0;
76 }
77
78 int Dinic(int s, int t)
79 {
80 int flow = 0;
81 while(1)
82 {
83 bfs(s);
84 if(lv[t] < 0) return flow;
85 memcpy(it, h, sizeof(it));
86 int f;
87 while((f = dfs(s, t, INF)) > 0) flow += f;
88 }
89 }
90
91 int a[11], G[11][11];
92 int main(void)
93 {
94 int N, M;
95 while(~scanf("%d %d", &N, &M))
96 {
97 if(!N) {puts("0"); continue;}
98 memset(G, 0, sizeof(G));
99 for(int i = 1; i <= M; i++)
100 {
101 int a, b;
102 scanf("%d %d", &a, &b);
103 G[a][b] = 1;
104 }
105
106 int ans = 0;
107 for(int i = 0; i < N; i++) a[i] = i + 1;
108 while(1)
109 {
110 init();
111 int S = N + N + 1, T = S + 1;
112 for(int i = 1; i <= N; i++) ad(S, i, 1), ad(N + i, T, 1);
113 for(int i = 1; i <= N; i++)
114 for(int j = 0; j < N; j++)
115 if(!G[i][a[j]] && !G[i][a[(j+1)%N]])
116 ad(i, N + 1 + j, 1);
117 ans = max(ans, Dinic(S, T));
118 if(!next_permutation(a + 1, a + N)) break;
119 }
120 printf("%d
", N - ans);
121 }
122 return 0;
123 }
Aguin
换匈牙利倒是快些。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 using namespace std;
6 int N, cnt, h[11];
7
8 struct edge
9 {
10 int to, pre;
11 } e[1111];
12
13 void init()
14 {
15 memset(h, -1, sizeof(h));
16 cnt = 0;
17 }
18
19 void add(int from, int to)
20 {
21 e[cnt].pre = h[from];
22 e[cnt].to = to;
23 h[from] = cnt;
24 cnt++;
25 }
26
27 // Hungary
28 int lk[11], vis[11];
29 bool dfs(int x)
30 {
31 for(int i = h[x]; i != -1; i = e[i].pre)
32 {
33 int to = e[i].to;
34 if(!vis[to])
35 {
36 vis[to] = 1;
37 if(lk[to] == -1 || dfs(lk[to]))
38 {
39 lk[to] = x;
40 return true;
41 }
42 }
43 }
44 return false;
45 }
46 int Hungary()
47 {
48 int ret = 0;
49 memset(lk, -1, sizeof(lk));
50 for(int i = 1; i <= N; i++)
51 {
52 memset(vis, 0, sizeof(vis));
53 if(dfs(i)) ret++;
54 }
55 return ret;
56 }
57
58
59 int a[11], G[11][11];
60 int main(void)
61 {
62 int M;
63 while(~scanf("%d %d", &N, &M))
64 {
65 if(!N) {puts("0"); continue;}
66 memset(G, 0, sizeof(G));
67 for(int i = 1; i <= M; i++)
68 {
69 int a, b;
70 scanf("%d %d", &a, &b);
71 G[a][b] = 1;
72 }
73
74 int ans = 0;
75 for(int i = 0; i < N; i++) a[i] = i + 1;
76 while(1)
77 {
78 init();
79 for(int i = 1; i <= N; i++)
80 for(int j = 0; j < N; j++)
81 if(!G[i][a[j]] && !G[i][a[(j+1)%N]])
82 add(i, 1 + j);
83 ans = max(ans, Hungary());
84 if(!next_permutation(a + 1, a + N)) break;
85 }
86 printf("%d
", N - ans);
87 }
88 return 0;
89 }
Aguin
1006 PowMod
1007 Rigid Frameworks
首先问题等价于求连通二分图数目。
据鸟神所说,m行n列的桁架,在第i行第j列加约束,使得:
①第i行的所有竖向杆件平行。
②第j列的所有横向杆件平行。
③第i行所有竖向杆件和第j列所有横向杆件垂直。
故只要对左边m个点,右边n个点建二分图,
只要二分图连通,则所有横向杆件平行,所有竖向杆件平行,所有横向杆件与所有纵向杆件垂直,即为刚体。
连通二分图计数问题,可以照着一般的连通图计数画葫芦。
参考:gyz营员交流
令$S(n, m)$为左边n个点,右边m个点的二分图数。
$F(n, m)$为左边n个点,右边m个点的连通二分图数。
$G(n, m) = S(n, m) - F(n, m)$
固定二分图左边的第一个点,考虑有多少个点与其连通,
$G(n, m) = sum_{i = 0}^{n - 1} sum_{j = 0, i + j
eq m + n - 1}^{m} C_{n-1}^{i}C_{m}^{j} F(i+1, j) S(n-i-1, m-j)$
而本题中对于i行j列的一个格子,可以选择不加约束,加左斜杠,加右斜杠。
故$S(n, m) = 3 ^ {nm}$
最后需要注意的是$F(n, m)$的边界条件。
1 #include <iostream>
2 #include <cstdio>
3 using namespace std;
4 typedef long long LL;
5 const LL mod = 1e9 + 7;
6 LL S[11][11], F[11][11], G[11][11];
7 LL c[11][11], p[111];
8
9 int main(void)
10 {
11 p[0] = 1LL;
12 for(int i = 1; i <= 100; i++) p[i] = p[i-1] * 3 % mod;
13
14 for(int i = 0; i <= 10; i++) c[i][0] = c[i][i] = 1;
15 for(int i = 1; i <= 10; i++)
16 for(int j = 1; j < i; j++)
17 c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
18
19 F[0][1] = F[1][0] = 1;
20 for(int i = 0; i <= 10; i++) S[0][i] = S[i][0] = 1;
21 for(int i = 1; i <= 10; i++)
22 for(int j = 1; j <= 10; j++)
23 {
24 for(int p = 0; p <= i - 1; p++)
25 for(int q = 0; q <= j && p + q != i + j - 1; q++)
26 G[i][j] = (G[i][j] + c[i-1][p] * c[j][q] % mod * F[p+1][q] % mod * S[i-p-1][j-q] % mod) % mod;
27
28 S[i][j] = p[i*j];
29 F[i][j] = (S[i][j] - G[i][j] + mod) % mod;
30 }
31
32
33 int m, n;
34 while(~scanf("%d %d", &m, &n)) printf("%I64d
", F[m][n]);
35 return 0;
36 }
Aguin
1008 Shell Necklace
1009 Solid Dominoes Tilings
1010 Subway
树同构,哈希一下就可以了。
题解的哈希方法以前看csy说过。
大概就是先找重心,每个点的孩子按哈希值排序算哈希值。
然而一开始两个素数随便取老冲突,于是以sz作为第二关键字排,就稳了。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <vector>
5 #include <algorithm>
6 #include <map>
7 using namespace std;
8 typedef long long LL;
9 const int maxn = 2e5 + 10;
10 const LL P = 1e6 + 7, Q = 1e9 + 7;
11 int N;
12
13 map<string, int> M1, M2;
14 string name[maxn];
15
16 // edge
17 int cnt, h[maxn];
18 void init()
19 {
20 cnt = 0;
21 memset(h, 0, sizeof(h));
22 }
23 struct edge
24 {
25 int to, pre;
26 } e[maxn<<1];
27 void add(int from, int to)
28 {
29 cnt++;
30 e[cnt].pre = h[from];
31 e[cnt].to = to;
32 h[from] = cnt;
33 }
34
35
36 // Node
37 struct node
38 {
39 int id, sz;
40 LL h;
41 node(int I, LL H, int S): id(I), h(H), sz(S) {}
42 friend bool operator < (node A, node B)
43 {
44 if(A.h != B.h) return A.h < B.h;
45 return A.sz < B.sz;
46 }
47 };
48
49
50 // dfs
51 int sz[maxn], M;
52 vector<int> G;
53 void dfs1(int x, int f)
54 {
55 sz[x] = 1;
56 int tmp = 0;
57 for(int i = h[x]; i; i = e[i].pre)
58 {
59 int to = e[i].to;
60 if(to == f) continue;
61 dfs1(to, x);
62 sz[x] += sz[to];
63 tmp = max(tmp, sz[to]);
64 }
65 tmp = max(tmp, N - sz[x]);
66 if(tmp < M)
67 {
68 M = tmp;
69 G.clear();
70 G.push_back(x);
71 }
72 else if(tmp == M) G.push_back(x);
73 }
74
75
76 LL H[maxn];
77 vector<node> v[maxn];
78 void dfs2(int x, int f)
79 {
80 sz[x] = 1;
81 v[x].clear();
82 for(int i = h[x]; i; i = e[i].pre)
83 {
84 int to = e[i].to;
85 if(to == f) continue;
86 dfs2(to, x);
87 sz[x] += sz[to];
88 v[x].push_back(node(to, H[to], sz[to]));
89 }
90
91 sort(v[x].begin(), v[x].end());
92 H[x] = 0;
93 int sv = v[x].size();
94 LL c = P;
95 if(!sv) H[x] = 1;
96 for(int i = 0; i < sv; i++)
97 {
98 H[x] = (H[x] + v[x][i].h * c) % Q;
99 c = c * P % Q;
100 }
101 }
102
103 void dfs3(int x1, int x2)
104 {
105 cout << name[x1] << ' ' << name[x2] << endl;
106 int sv = v[x1].size();
107 for(int i = 0; i < sv; i++) dfs3(v[x1][i].id, v[x2][i].id);
108 }
109
110 int main(void)
111 {
112
113 ios::sync_with_stdio(0);
114
115 while(cin >> N)
116 {
117 init();
118 M1.clear(), M2.clear();
119 int num = 0;
120
121 for(int i = 1; i < N; i++)
122 {
123 string a, b;
124 cin >> a >> b;
125 if(!M1[a]) M1[a] = ++num, name[num] = a;
126 if(!M1[b]) M1[b] = ++num, name[num] = b;
127 add(M1[a], M1[b]), add(M1[b], M1[a]);
128 }
129
130 M = N + 1;
131 dfs1(1, 0);
132 dfs2(G[0], 0);
133 int rt1 = G[0];
134
135 for(int i = 1; i < N; i++)
136 {
137 string a, b;
138 cin >> a >> b;
139 if(!M2[a]) M2[a] = ++num, name[num] = a;
140 if(!M2[b]) M2[b] = ++num, name[num] = b;
141 add(M2[a], M2[b]), add(M2[b], M2[a]);
142 }
143
144 M = N + 1;
145 dfs1(N + 1, 0);
146 dfs2(G[0], 0);
147 int rt2 = G[0];
148 if(H[rt1] != H[G[0]]) dfs2(G[1], 0), rt2 = G[1];
149
150 dfs3(rt1, rt2);
151
152 }
153 return 0;
154 }
Aguin
1011 tetrahedron