安徽大学第九届程序设计竞赛决赛题解
A.调酒师
很水的一道题,算出每个参数的最小值就行,手速选手被碾压的开始QAQ。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() { 5 //freopen("in.txt", "r", stdin); 6 int T; 7 int n, a, b, c, d, e, f, g; 8 cin >> T; 9 while (T--) { 10 cin >> n; 11 cin >> a >> b >> c >> d >> e >> f >> g; 12 int A = a * b; 13 int B = c * d; 14 int a1, a2, a3; 15 a1 = A / f; a2 = B; a3 = e / g; 16 int ans = min(a1, min(a2, a3)); 17 cout << ans / n << endl; 18 } 19 20 return 0; 21 }
B.下一个幸运数
本场比赛难度第三的题目,一开始当成数位DP做,一个半小时debug无果,最后发现幸运数总共就1000多个,存起来暴力扫描相加就行 。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 vector<ll> vec; 5 vector<ll>::iterator it; 6 set<ll> ss; 7 char s[15]; 8 9 void dfs(int cur, bool zero, ll sum) { 10 if (cur == 11) return; 11 if (!ss.count(sum)) { 12 ss.insert(sum); 13 vec.push_back(sum); 14 } 15 if (zero) { 16 dfs(cur+1, 1, 0); 17 dfs(cur+1, 0, 4); 18 dfs(cur+1, 0, 7); 19 } 20 else { 21 dfs(cur+1, 0, sum*10+4); 22 dfs(cur+1, 0, sum*10+7); 23 } 24 } 25 26 int main() { 27 dfs(0, 1, 0); 28 sort(vec.begin(), vec.end()); 29 it = vec.begin(); 30 int T; 31 cin >> T; 32 while (T--) { 33 ll l, r; 34 cin >> l >> r; 35 int cnt = 0, len = vec.size(); 36 for (int i = 0; i < len; ++i, ++cnt) if (l <= vec[i]) break; 37 int xx = min(vec[cnt], r) - l + 1; 38 ll ans = xx * vec[cnt]; 39 //cout << xx << endl; 40 ll temp = vec[cnt]; 41 int cnt2 = cnt + 1; 42 for (int i = cnt + 1; i < len; ++i, ++cnt2) { 43 if (vec[i] > r) break; 44 int yy = vec[i] - temp; 45 temp = vec[i]; 46 ans += yy * vec[i]; 47 } 48 if (vec[cnt2-1] < r) { 49 int zz = r-vec[cnt2-1]; 50 ans += zz * vec[cnt2]; 51 } 52 cout << ans << endl; 53 } 54 55 return 0; 56 }
C.最短路径和
做出这道题目需要灵活掌握Floyd的原理,比赛时只会个形式便没写出来。实际上只需要记录删点的次序,倒叙用来当中转点更新路径,统计ans的时候只统计目前存在的点。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define M(a, b) memset(a, b, sizeof(a)) 4 #define INF 0x3f3f3f3f 5 typedef long long ll; 6 const int N = 400 + 5; 7 int G[N][N], d[N][N], n, q[N], ans[N]; 8 9 void Floyd() { 10 M(ans, 0); 11 for (int kk = n; kk >= 1; --kk) { 12 int k = q[kk]; 13 for (int i = 1; i <= n; ++i) 14 for (int j = 1; j <= n; ++j) { 15 d[i][j] = min(d[i][j], d[i][k]+d[k][j]); 16 } 17 for (int i = kk; i <= n; ++i) 18 for (int j = kk; j <= n; ++j) 19 ans[kk] += d[q[i]][q[j]]; 20 } 21 cout << ans[1]; 22 for (int i = 2; i <= n; ++i) cout << " " << ans[i]; 23 cout << endl; 24 } 25 26 int main() { 27 ios::sync_with_stdio(false); 28 while (cin >> n) { 29 M(G, 0); M(d, INF); 30 for (int i = 1; i <= n; ++i) 31 for (int j = 1; j <= n; ++j) 32 cin >> d[i][j]; 33 for (int i = 1; i <= n; ++i) cin >> q[i]; 34 Floyd(); 35 } 36 37 return 0; 38 }
D. 西瓜的编译原理作业
贼裸的字典树,不需要任何技巧,不会字典树拿指针模拟都可以做。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 0x3f3f3f3f 4 #define M(a, b) memset(a, b, sizeof(a)) 5 #define idx(a) a - 'A' 6 const int maxn = 5000 + 10; 7 int ch[maxn*70][27], val[maxn*70], tot; 8 char s[100]; 9 10 void Insert(char *s) { 11 int now = 0, len = strlen(s), id; 12 for (int i = 0; i < len; ++i) { 13 id = idx(s[i]); 14 if (!ch[now][id]) ch[now][id] = ++tot; 15 now = ch[now][id]; 16 } 17 val[now] = 1; 18 } 19 20 int ans = 0; 21 void dfs(int now) { 22 ans++; 23 for (int i = 0; i < 26; ++i) 24 if (ch[now][i]) dfs(ch[now][i]); 25 } 26 27 int main() { 28 //freopen("D://in.txt", "r", stdin); 29 while (cin >> s) { 30 Insert(s); 31 } 32 dfs(0); 33 cout << ans << endl; 34 35 return 0; 36 }
E. 晋级下一轮
排序
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[200]; 4 5 bool cmp(int a, int b) {return a > b;} 6 7 int main() { 8 //freopen("D://in.txt", "r", stdin); 9 int T; 10 int n, k; 11 cin >> T; 12 while (T--) { 13 cin >> n >> k; 14 for (int i = 0; i < n; ++i) cin >> a[i]; 15 sort(a, a+n, cmp); 16 int cnt = 1; 17 int temp = a[0], kk; 18 int i; 19 bool flag = 0; 20 kk = a[k-1]; 21 //cout << kk << endl; 22 int ans = 0; 23 for (int i = 0; i < n; ++i) if (a[i] >= kk && a[i]) ++ans; 24 cout << ans << endl; 25 } 26 27 return 0; 28 }
F. 西瓜和病毒
把特征串建立成AC自动机,再从root开始跑,如果存在一个环(环的路径上不包括任何特征串,也就是不经过val值为1的点),就存在一个安全串,这题的一个trick就是如果某个点u的失配指针f[u]的val为1,要把val[u]也赋值为1,因为root~f[u]为root~u的后缀。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define idx(a) a - '0' 4 #define M(a, b) memset(a, b, sizeof(a)) 5 #define INF 0x3f3f3f3f 6 const int N = 30000 + 5; 7 char s[N]; 8 9 struct ac_mata { 10 int ch[N][2], f[N], in[N], val[N], tot; 11 bool vis[N]; 12 13 void init() { 14 tot = 0; 15 M(f, 0); M(in, 0); M(vis, 0); M(val, 0); M(ch, 0); 16 } 17 18 void insert(char *s) { 19 int now = 0, id, len = strlen(s); 20 for (int i = 0; i < len; ++i) { 21 id = idx(s[i]); 22 if (!ch[now][id]) ch[now][id] = ++tot; 23 now = ch[now][id]; 24 } 25 val[now] = 1; 26 } 27 28 void getFail() { 29 queue<int> q; 30 int u; 31 for (int i = 0; i < 2; ++i) { 32 u = ch[0][i]; 33 if (u) {f[u] = 0; q.push(u);} 34 } 35 while (!q.empty()) { 36 u = q.front(); q.pop(); 37 for (int i = 0; i < 2; ++i) { 38 int v = ch[u][i]; 39 if (!v) {ch[u][i] = ch[f[u]][i]; continue;} 40 q.push(v); 41 int k = f[u]; 42 if (k && !ch[k][i]) k = f[k]; 43 f[v] = ch[k][i]; 44 val[v] |= val[f[v]]; 45 } 46 } 47 } 48 49 bool findcircle(int x) { 50 in[x] = 1; 51 for (int i = 0; i < 2; ++i) { 52 int u = ch[x][i]; 53 if (in[u]) return 1; 54 if (vis[u] || val[u]) continue; 55 vis[u] = 1; 56 if (findcircle(u)) return 1; 57 } 58 in[x] = 0; 59 return 0; 60 } 61 62 }ac; 63 64 int main() { 65 ios::sync_with_stdio(false); 66 int n; 67 while (cin >> n) { 68 ac.init(); 69 while (n--) { 70 cin >> s; 71 ac.insert(s); 72 } 73 ac.getFail(); 74 if (ac.findcircle(0)) cout << "TAK" << endl; 75 else cout << "NIE" << endl; 76 } 77 78 return 0; 79 }
G. 黑白棋
大水题,题面把行写成了列,debug很久,头皮发麻。
1 #include<bits/stdc++.h> 2 using namespace std; 3 char s[20]; 4 char a[12][12]; 5 bool b[13]; 6 vector<int> vec; 7 8 int main() { 9 //freopen("D://in.txt", "r", stdin); 10 int n; 11 cin >> n; 12 while (n--) { 13 memset(b, 0, sizeof(b)); 14 vec.clear(); 15 int ans = 0; 16 scanf("%s", s+1); 17 bool flag = 0; 18 for (int j = 1; j <= 12; j++) { 19 if (12 % j) continue; 20 for (int i = 1; i <= j; ++i) { 21 flag = 1; 22 for (int k = i; k <= 12; k += j) 23 if (s[k] == 'O') flag = 0; 24 if (flag) break; 25 } 26 if (flag) vec.push_back(j), ++ans; 27 } 28 cout << ans; 29 for (int i = vec.size()-1; i >= 0; --i) { 30 int c = vec[i]; 31 cout << " " << 12 / c << "x" << c; 32 } 33 cout << endl; 34 } 35 36 return 0; 37 }
H. 勤劳的出题人
两个指针指向两个数组,一一比较,最后总数减去成功匹配的数量即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3000 + 10; 4 int a[maxn], b[maxn]; 5 bool vis[maxn], have[1000010]; 6 7 int main() { 8 //freopen("D://in.txt", "r", stdin); 9 int n, m; 10 while (cin >> n >> m) { 11 memset(have, 0, sizeof(have)); 12 memset(vis, 0, sizeof(vis)); 13 for (int i = 1; i <= n; ++i) cin >> a[i]; 14 for (int j = 1; j <= m; ++j) { 15 cin >> b[j]; 16 } 17 sort(a+1, a+n+1); 18 sort(b+1, b+m+1); 19 int cnt = 0; 20 int i = 1, j = 1; 21 while (i <= n && j <= m){ 22 if (a[i] <= b[j]) { 23 ++i; 24 ++j; 25 ++cnt; 26 } 27 else ++j; 28 } 29 cout << n - cnt << endl; 30 } 31 32 return 0; 33 }