A. 比大小
思路:直接比较大小关系,模拟题意输出
#include <iostream> using namespace std; int main() { int a, b; cin >> a >> b; if (a > b) cout << '>' << endl; if (a < b) cout << '<' << endl; if (a == b) cout << '=' << endl; return 0; }
B. 不满的大臣
思路:可以证明,找k个大臣一定比找k+1个大臣最优,因为每次只能最先见一个人,如果找k+1个大臣,会比找k个大臣使得重复第一个面见同一个人的概率增加。以此类推,每次找一个大臣是最优的方案,那么只需要每次都找一个还没满意的大臣使他满意即可,答案为大臣数量
#include <iostream> using namespace std; int main() { long n; cin >> n; cout << n << endl; return 0; }
C. 众字母
思路:读取字符串时,不能使用cin,因为cin无法读入空格,要使用getline,在处理字符串的时候用一个字符型变量存储答案。
#include <bits/stdc++.h> using namespace std; string s; map <char, int> mp; int main() { getline(cin, s); int ans = 0; char c; for (int i = 0; i < s.size(); i++) { if ((s[i] < 'a' || s[i]>'z') && (s[i] < 'A' || s[i]>'Z')) continue; mp[s[i]]++; if (mp[s[i]] > ans) { ans = mp[s[i]]; c = s[i]; } else if (mp[s[i]] == ans && s[i] < c) { c = s[i]; } } printf("%c", c); }
D. 好数
思路:本题方法与新生训练题2中的水仙花数方法基本一致,用到了枚举法,然后再按题意处理即可。
#include <iostream> using namespace std; int main() { int t, l, r, ans; cin >> t; while (t--) { cin >> l >> r; ans = 0; for (int i = l; i <= r; i++) { if ((i / 100) * (i / 10) % 10 == i % 10) ans++; } cout << ans << endl; } return 0; }
E. 完美数
思路:本题用到了贪心算法,易知需要找最大的数位和最小的数位,判断是否能够用若干个完美数得到答案,如果可以,用最大的数位除以2就是答案(向上取整)
补充:为了简化本题,n的范围上限只设置了1e18,算法能够解决的数据范围远远大于此。
#include <iostream> #include <string> #include <algorithm> using namespace std; string s; int main() { ios::sync_with_stdio(false); cin >> s; int maxx = -1; int minn = 11; for (int i = 0; i < s.size(); i++) { maxx = max(maxx, s[i] - '0'); minn = min(minn, s[i] - '0'); } if (minn * 2 < maxx) { cout << -1 << endl; return 0; } int ans = maxx / 2; if (maxx & 1) ans++; cout << ans << endl; }
F. 劳累的造物主
思路:假如第一个地盘净出生人数大于0,那么它一定通过2-n转世过来,无论通过那边转世过来,一定会经过2,那么就等价于是2转世过来的,再给2地盘的数量减去第一个地盘的净出生人数即可,以此类推扩展到其他地盘。若第一个地盘净死亡人数大于0,也可以用同样的方法得到同样的结论。
#include <iostream> using namespace std; #define ll long long int main() { int n; while (scanf("%d", &n) != EOF) { if (n == 0) break; ll ans = 0; ll last = 0; for (int i = 1; i <= n; i++) { ll tmp; scanf("%lld", &tmp); ans += abs(last); last += tmp; } printf("%lld\n", ans); } }
G. 游戏
思路:我们先来看看最后一步,假设最后一步是Bob操作,那么无论剩下两个数的奇偶性如何,他都可以把数变成偶数,这对应了初始奇数个数字的情况。换句话说,当n为奇数时,Bob必胜(n=1要根据唯一的数字的奇偶性特判)。否则,最后一步是Alice操作,除了两个数字都是偶数的情况,Alice都能把最后的结果变成奇数。那我们在意的是每时每刻剩下多少个偶数,Alice每次操作最多可以消灭一个偶数,Bob每次操作最多可以生成一个偶数。所以如果初始的偶数数目至少有两个,那么Alice是赢不了的(无论什么时候Alice消灭偶数,如果此时有两个奇数,bob都能生成一个偶数。如果alice消灭偶数后仅剩1个或0个奇数,bob可以转而消灭那个奇数,这样所有的数字都是偶数了。)。当初始偶数小于2个时,Alice必胜(Bob没办法让最后的偶数个数达到2个)。
标程:
#include <iostream> #include <cstdio> #include <set> #include <string.h> #include <algorithm> #include <vector> #include <cstring> #include <unordered_map> #include <queue> using namespace std; int main() { int n; scanf("%d", &n); int ji = 0, ou = 0; for (int i = 1; i <= n; i++) { int tmp; scanf("%d", &tmp); if (tmp & 1) ji++; else ou++; } if (ji == 2 && ou == 0) { printf("0\n"); } else if ((ou >= 2) || (ou == 1 && ji % 2 == 0) || (ou == 0 && (ji != 1 && (ji & 1)))) { printf("1\n"); } else printf("0\n"); }
优秀选手代码:
#include<iostream> #include<cstdio> #include<iostream> #include<cstdio> #include<cmath> using namespace std; int n, s, a, b; int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &s); if (s & 1) ++a; else ++b; } if (n == 1) { if (a) printf("0"); else printf("1"); return 0; } if (n & 1) { printf("1"); return 0; } for (int i = 1; i < (n - 1); i += 2) { if (b) --b; else --a; a -= 2, ++b; } if (a > 0) printf("0"); else printf("1"); return 0; }
H. 诸侯鼎立
思路:枚举+搜索回溯
#include <bits/stdc++.h> using namespace std; int n; int a[65]; bool vis[65]; int sum = 0;//记录士兵的能力值 //枚举可能的答案,如果sum%i==0答案才有可能正确,否则直接跳过 //并且答案一定比最大的士兵能力值要大 void init() { memset(a, 0, sizeof(a)); memset(vis, 0, sizeof(vis)); sum = 0; } bool cmp(int x, int y) { return x > y; } bool dfs(int k, int step, int len, int rest)//k为已经分配好的士兵数量,len为诸侯能力值,rest为剩余待招募士兵能力值 { if (k - 1 == n && rest == 0) return true;//士兵用完,并且诸侯能力值达到 else if (rest == 0)//诸侯能力值达到了,士兵还没用完 { rest = len;//找一个新的士兵来招募 step = 0; } else if (k - 1 == n)//士兵用完了,诸侯的能力值不符合要求,说明这个答案是错误的,没法拼凑好诸侯的能力 return false; for (int i = step + 1; i <= n; i++) { if (!vis[i] && a[i] <= rest)//如果士兵没用过并且用上这个士兵以后不会使整个木棒长度大于len { vis[i] = true; if (dfs(k + 1, i, len, rest - a[i])) return true; vis[i] = false; if (len == rest || a[i] == rest) //头尾剪枝 break; while (a[i] == a[i + 1]) i++;//换用的新士兵一定不能跟之前淘汰的士兵一样 } } return false;//如果枚举完以后都没有拼接成功,说明失败了 } int main() { int t; scanf("%d", &t); while (t--) { init(); scanf("%d", &n); for (int i = 1; i <= n;) { scanf("%d", &a[i]); sum += a[i]; i++; } sort(a + 1, a + 1 + n, cmp); for (int i = a[1]; i <= sum; i++)//由于要求的是最小诸侯能力值,所以从最小可能答案一直枚举到最大可能答案 { if (sum % i != 0) continue; if (dfs(1, 0, i, i))//dfs检验这个答案是否正确,接下来完成dfs函数的编写 //如果正确,直接输出这个答案并且跳出循环 { printf("%d\n", i); break; } } } }
I. 温馨的集训队
思路:最小生成树+按题意模拟即可
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> using namespace std; int a[10010]; struct ty { int s, t, l; }edge[100010]; int n, p; int fa[10010]; bool comp(ty a, ty b) { return a.l < b.l; } int findfa(int x) { return fa[x] == x ? x : fa[x] = findfa(fa[x]); } void merge(int x, int y) { int fx = findfa(x); int fy = findfa(y); fa[fx] = fa[fy]; } int kruskal() { for (int i = 1; i <= n; i++) fa[i] = i; sort(edge + 1, edge + 1 + p, comp); int sum = 0, cnt = 0; for (int i = 1; i <= p; i++) { int x = edge[i].s, y = edge[i].t; if (findfa(x) != findfa(y)) { merge(x, y); sum += edge[i].l; cnt++; } if (cnt >= n - 1) break; } return sum; } int main() { while (scanf("%d%d", &n, &p) != EOF && n != 0 && p != 0) { int minn = 0x7f7f7f7f; for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); minn = min(a[i], minn); } for (int i = 1; i <= p; i++) { scanf("%d%d%d", &edge[i].s, &edge[i].t, &edge[i].l); edge[i].l = edge[i].l * 2 + a[edge[i].s] + a[edge[i].t]; } printf("%d\n", kruskal() + minn); } return 0; }