A:三个数找中间大
- void solve() {
- vector<int> a(3);
- rep(i, 0, 3) cin >> a[i];
- sort(all(a));
- cout << a[1] << endl;
- }
B:问你字符串中最大的字母对应编号
- void solve() {
- int n; cin >> n;
- string s; cin >> s;
- char c = 'a';
- for (auto x : s) c = max(c, x);
- cout << c - 'a' + 1 << endl;
- }
C:问你每个数与最大值的差, 最大值则与第二大的特判
- void solve() {
- int n; cin >> n;
- int mx1 = -1e8, mx2 = -1e8;
- for (int i = 1; i <= n; i ++ ) {
- cin >> a[i];
- if(a[i] > mx1) mx2 = mx1, mx1 = a[i];
- else if(a[i] > mx2) mx2 = a[i];
- }
- for (int i = 1; i <= n; i ++ ) {
- if(a[i] != mx1) cout << a[i] - mx1 << ' ';
- else cout << mx1 - mx2 << ' ';
- }
- cout << endl;
- }
D:问你当前这个数组是不是有谷
- void solve() {
- int n; cin >> n;
- repn(i, 1, n) cin >> a[i];
- bool fg = false;
- for (int i = 2; i <= n; i ++ ) {
- if(a[i] == a[i - 1]) continue;
- if(fg) {
- if(a[i] < a[i - 1]) {cout << "NO" << endl; return;}
- }
- if(a[i] > a[i - 1]) fg = true;
- }
- cout << "YES" << endl;
- }
E:给你一个01串,你最多可以修改一个位置,将0->1, 1->0,问你最大的逆序对数量。
思路:先处理出原始的逆序对数量。然后分分别枚举每一个位置
1->0:ans减去后缀0的数量,加上前缀1的数量
0->1:ans加上后缀0的数量,减去前缀1的数量。
- void solve() {
- int n; cin >> n;
- for (int i = 0; i <= n + 20; i ++ ) pre1[i] = pre0[i] = end0[i] = end1[i] = 0;
- map<int, int> mp;
- ll ans = 0;
- for (int i = 1; i <= n; i ++ ) {
- cin >> a[i];
- mp[a[i]] ++;
- if(a[i] == 0) ans += mp[1];
- }
-
-
- if(a[1] == 0) pre0[1] = 1;
- else pre1[1] = 1;
- for (int i = 2; i <= n; i ++ ) {
- pre0[i] = pre0[i - 1] + (a[i] == 0);
- pre1[i] = pre1[i - 1] + (a[i] == 1);
- }
-
-
- if(a[n] == 0) end0[n] = 1;
- else end1[n] = 1;
- for (int i = n - 1; i >= 0; i -- ) {
- end0[i] = end0[i + 1] + (a[i] == 0);
- end1[i] = end1[i + 1] + (a[i] == 1);
- }
- ll tmp = ans;
- for (int i = 1; i <= n; i ++ ) {
- if(a[i] == 1) {
- ans = max(ans, tmp - end0[i + 1] + pre1[i - 1]);
- }
- else ans = max(ans, tmp + end0[i + 1] - pre1[i]);
- //cout << ans << endl;
- }
- cout << ans << endl;
-
- }
F:你有n个工作,每个工作对应ai的收益。你还有一个c和一个d,d是deadline。现在,完成了一个工作会有一个约束,即k天内无法再次做这个工作。现在问你d天内,我们是否可以最大化k,使得收益达到c。
思路:很明显的二分答案。我们可以二分这个答案k。贪心的考虑,我们每次肯定都是先做收益ai最大的工作。所以排个序,取模随便搞一搞就行了。注意一下define int long long
- void solve() {
- cin >> n >> c >> d;
- for (int i = 1;i <= n; i++ ) cin >> a[i];
- int sum = 0, mx = 0;
- for (int i = 1; i <= n; i++ ) sum += a[i], mx = max(mx, a[i]);
- if(mx * d < c) {cout << "Impossible" << endl; return;}
- sort(a + 1, a + n + 1);
- int l = 0, r = INF;
-
- auto check = [&](int mid) {
- int res = 0;
- for (int i = n; i >= max(n - mid, 1ll); i --) res += a[i];
- int sum = 0;
- for (int i = n, j = d % (mid + 1); j >= 1 && i >= max(n - mid, 1ll); i --, j -- ) sum += a[i];
-
- return d / (mid + 1) * res + sum >= c;
- };
- while(l < r) {
- int mid = l + r + 1 >> 1;
- if(check(mid)) l = mid;
- else r = mid - 1;
- }
- if(r < INF) cout << r << endl;
- else cout << "Infinity" << endl;
- }
G:有一棵树,每条树边有一个权值w,问你从a走到b,是否能使得边的权值异或是0,但是中间你可以随便跳一次。也是在路上随便位移到另外一个点。
思路:从a开始不到b跑一边前缀异或值,放入set或者map。然后从b再出发随便跑一遍,记录异或值。如果异或值已经出现了,说明我们直接瞬移到这个点然后走回去就是0了。
- vector
int, 2>> e[N]; - int ans;
- bool fg;
- map<int, int> mp;
-
- void solve() {
- cin >> n >> a >> b;
- mp.clear();
- for (int i = 0; i <= n + 10; i ++ ) e[i].clear();
- for (int i = 1; i < n; i ++ ) {
- int a, b, c; cin >> a >> b >> c;
- e[a].pb({b, c});
- e[b].pb({a, c});
- }
- auto dfs = [&](auto&& self, int u, int fa, int cur) -> void {
- mp[cur] = 1;
- for (auto [to, v]: e[u]) {
- if(to == fa) continue;
- if(to == b) continue;
- self(self, to, u, cur ^ v);
- }
- };
-
- auto dfs2 = [&](auto&& self, int u, int fa, int cur) -> void {
- for (auto [to, v] : e[u]) {
- if(to == fa) continue;
- self(self, to, u, cur ^ v);
- if(fg) return ;
- if(mp[cur ^ v]) {
- fg = true;
- cout << "YES" << endl;
- }
- }
- };
-
- dfs(dfs, a, 0, 0);
- fg = false;
- dfs2(dfs2, b, 0, 0);
- if(!fg) {cout << "NO" << endl; return;};
-
- }