codeforces round #414 div1+div2
A:判断一下就可以了
#include<bits/stdc++.h> using namespace std; typedef long long ll; int a, b, c, n; ll ans; int main() { scanf("%d%d%d%d", &a, &b, &c, &n); for(int i = 1; i <= n; ++i) { int x; scanf("%d", &x); if(x > b && x < c) ++ans; } printf("%lld\n", ans); return 0; }
B:1:sqrt(2)-1....
#include<bits/stdc++.h> using namespace std; int n; double f; int main() { scanf("%d%lf", &n, &f); double t = f / (double)sqrt(n); for(int i = 1; i < n; ++i) { printf("%.15f ", t * (double)sqrt(i)); } return 0; }
C:贪心,第一个字符串只用前n-[n/2]个,后一个字符串只用后[n/2]个,每个字符串用两个指针,如果第一个字符串最小的比第二个字符串最大的小,那么第一个人将最小的字符放在最靠前的位置,同理第二个人将最大的字符放在最前的位置,如果第一个人最小的字符比第二个人最大的字符大,那么就把他最大的字符放在末尾,第二个人则将最小的字符放在末尾。
#include<bits/stdc++.h> using namespace std; const int N = 300010; int n; int cnt1[N], cnt2[N], ans[N]; char s[N], t[N]; int main() { scanf("%s%s", s + 1, t + 1); n = strlen(s + 1); for(int i = 1; i <= n; ++i) ++cnt1[s[i] - 'a']; for(int i = 1; i <= n; ++i) ++cnt2[t[i] - 'a']; int pos1 = 0, pos2 = 25, l = 0, r = n + 1; for(int i = 1; i <= n; ++i) { while(cnt1[pos1] == 0) ++pos1; while(cnt2[pos2] == 0) --pos2; if(i % 2 == 1) { if(pos1 < pos2) ans[++l] = pos1; else ans[--r] = pos1; --cnt1[pos1]; } else { if(pos1 < pos2) ans[++l] = pos2; else ans[--r] = pos2; --cnt2[pos2]; } } for(int i = 1; i <= n; ++i) printf("%c", (char)(ans[i] + 'a')); return 0; }
D:重点在于会有相同的颜色,如果没有的话,那么直接染色就可以了,因为这样限制是唯一的,一个点颜色为i,相邻只能用两种颜色i-1和i+1,那么很好办。这里我们用一个巧妙的办法去除相同颜色,一个点将自己放入自己的邻接表中,然后排序邻接表,如果两个点的邻接表相同那么他们肯定相邻,那么这两个点的颜色相同。我们设一个点的颜色为i,另一个点的颜色为i+1,那么相邻的点的颜色只能等于i或i+1,如果等于i-1或i+2的话肯定和两个点中的一个矛盾,那么既然所有的邻居都等于i或i+1,那么我们不妨把那个颜色为i+1的点颜色换为i,很显然不矛盾。然后我们就把颜色能够相同的点分类,画成一个大点,重新编号,构图,两个新的点相邻当且仅当他们的点集中有相邻的点,也就是说这两个点集是相邻的。这里我们可以知道如果一个新的点的度数>=3或者有环就是无解,否则直接染色。
#include<bits/stdc++.h> using namespace std; const int N = 600010, MaxCH = 20000000; int n, m, pos, len; char CH[MaxCH]; vector<int> G[N]; int fa[N], color[N], Hash[N], h[N], u[N], v[N], used[N], vis[N]; inline int read() { int x = 0; while(CH[pos] < '0' || CH[pos] > '9') ++pos; while(CH[pos] >= '0' && CH[pos] <= '9') x = x * 10 + CH[pos++] - '0'; return x; } namespace dsu { inline int find(int x) { return x == fa[x] ? x : find(fa[x]); } inline void connect(int x, int y) { int u = find(x), v = find(y); if(u == v) return; fa[u] = v; } } using namespace dsu; void build() { for(int i = 1; i <= m; ++i) if(h[u[i]] == h[v[i]]) connect(u[i], v[i]); for(int i = 1; i <= m; ++i) { int x = find(u[i]), y = find(v[i]); if(x == y) continue; G[x].push_back(y); G[y].push_back(x); } for(int i = 1; i <= n; ++i) { sort(G[i].begin(), G[i].end()); G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end()); if(G[i].size() > 2) { puts("NO"); exit(0); } } } void dfs(int u, int last) { used[color[u]] = 1; vis[u] = 1; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(v == last) continue; if(vis[v]) { puts("NO"); exit(0); } if(!used[color[u] - 1]) color[v] = color[u] - 1; else color[v] = color[u] + 1; used[color[v]] = 1; dfs(v, u); } } int main() { len = fread(CH, 1, MaxCH, stdin); CH[len] = ' '; n = read(); m = read(); Hash[0] = 1; for(int i = 1; i <= n; ++i) Hash[i] = Hash[i - 1] * 123333, fa[i] = i, h[i] = Hash[i]; for(int i = 1; i <= m; ++i) { u[i] = read(); v[i] = read(); h[u[i]] += Hash[v[i]]; h[v[i]] += Hash[u[i]]; } build(); color[find(1)] = 300000; dfs(find(1), 0); puts("YES"); for(int i = 1; i <= n; ++i) printf("%d ", color[find(i)]); return 0; }
E:我们可以知道假设我们二分答案x,把>=x的数标为1,<x的数标为0,那么第一个人就是想要剩下的一个数为1,第二个人反之。那么我们可以知道两个性质:
1.如果n为奇数,那么当且仅当中间的数等于1和他任意相邻的两个数其中为1的情况下第一个人能赢,也就是说x能取到
2.如果n为偶数,那么当且仅当中间的两个数都为1第一个人才能赢,也就是说x能取到
然后我们发现,既然对于任意一个x根据n必须满足上面的条件才能赢,那么也就是说答案只跟中间的几个数有关,因为一个答案必须满足使中间的数满足条件才可以
所以我们就有答案
n为奇数ans=min(a[t],max(a[t-1],a[t+1]))t=(n+1)/2,因为我们可以保住中间的数和两边的数之一,我们不能自己选择保哪个,只可意会不可言传,自己手画画就可以了。
n为偶数ans=max(a[t],a[t+1])t=n/2,保哪个数可以自己选择,手画一下就可以了。
对于取了k个我们只需要看每段连续n-k个元素的最大值就好了
#include<bits/stdc++.h> using namespace std; const int N = 300010; int n; int a[N], b[N], c[N], ans[N]; struct seg { int tree[N << 2]; void build(int l, int r, int x, int *a) { if(l == r) { tree[x] = a[l]; return; } int mid = (l + r) >> 1; build(l, mid, x << 1, a); build(mid + 1, r, x << 1 | 1, a); tree[x] = max(tree[x << 1], tree[x << 1 | 1]); } int query(int l, int r, int x, int a, int b) { if(l > b || r < a) return 0; if(l >= a && r <= b) return tree[x]; int mid = (l + r) >> 1; return max(query(l, mid, x << 1, a, b), query(mid + 1, r, x << 1 | 1, a, b)); } } t1, t2; int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); for(int i = 1; i <= n; ++i) { ans[n - 1] = max(ans[n - 1], a[i]); b[i] = min(a[i], max(a[i - 1], a[i + 1])); c[i] = max(a[i], a[i + 1]); } t1.build(1, n, 1, b); t2.build(1, n, 1, c); int l1, r1, l2, r2; if(n % 2 == 0) { l1 = n / 2; r1 = l1 + 1; l2 = r2 = n / 2; } else { l1 = r1 = (n + 1) / 2; l2 = n / 2; r2 = l2 + 1; } for(int k = 0; k < n - 1; ++k) if((n - k) % 2 == 1) ans[k] = t1.query(1, n, 1, l1--, r1++); else ans[k] = t2.query(1, n, 1, l2--, r2++); for(int i = 0; i < n; ++i) printf("%d ", ans[i]); return 0; }
F:线段树维护每位,调了好长时间,原因是要在程序顶端先pushdown一下,我没有这个习惯
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 200010; struct data { ll cnt[20]; int nxt[20]; } tree[N << 2]; int n, q; int a[N]; ll bin[20]; void pushdown(int x) { static ll cnt[10]; static int nxt1[10], nxt2[10]; memset(cnt, 0, sizeof(cnt)); memset(nxt1, 0, sizeof(nxt1)); memset(nxt2, 0, sizeof(nxt2)); for(int i = 0; i <= 9; ++i) { nxt1[i] = tree[x].nxt[tree[x << 1].nxt[i]]; nxt2[i] = tree[x].nxt[tree[x << 1 | 1].nxt[i]]; } for(int i = 0; i <= 9; ++i) { tree[x << 1].nxt[i] = nxt1[i]; tree[x << 1 | 1].nxt[i] = nxt2[i]; } for(int i = 0; i <= 9; ++i) cnt[tree[x].nxt[i]] += tree[x].cnt[i]; for(int i = 0; i <= 9; ++i) { tree[x].cnt[i] = cnt[i]; tree[x].nxt[i] = i; } } void build(int l, int r, int x) { if(l == r) { int t = a[l], pos = -1; while(t) { tree[x].cnt[t % 10] += bin[++pos]; t /= 10; } for(int i = 0; i <= 9; ++i) tree[x].nxt[i] = i; return; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); for(int i = 0; i <= 9; ++i) tree[x].cnt[i] = tree[x << 1].cnt[i] + tree[x << 1 | 1].cnt[i]; for(int i = 0; i <= 9; ++i) tree[x].nxt[i] = i; } void update(int l, int r, int x, int a, int b, int x1, int y1) { pushdown(x); if(l > b || r < a) return; if(l >= a && r <= b) { tree[x].nxt[x1] = y1; pushdown(x); return; } int mid = (l + r) >> 1; update(l, mid, x << 1, a, b, x1, y1); update(mid + 1, r, x << 1 | 1, a, b, x1, y1); for(int i = 0; i <= 9; ++i) tree[x].cnt[i] = tree[x << 1].cnt[i] + tree[x << 1 | 1].cnt[i]; } ll query(int l, int r, int x, int a, int b) { pushdown(x); if(l > b || r < a) return 0; if(l >= a && r <= b) { ll ans = 0; for(int i = 0; i <= 9; ++i) ans += (ll)i * tree[x].cnt[i]; return ans; } int mid = (l + r) >> 1; ll x1, x2; pushdown(x); x1 = query(l, mid, x << 1, a, b); x2 = query(mid + 1, r, x << 1 | 1, a, b); return x1 + x2; } int main() { scanf("%d%d", &n, &q); bin[0] = 1; for(int i = 1; i <= 16; ++i) bin[i] = bin[i - 1] * 10; for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); build(1, n, 1); while(q--) { int opt, l, r, x, y; scanf("%d", &opt); if(opt == 1) { scanf("%d%d%d%d", &l, &r, &x, &y); update(1, n, 1, l, r, x, y); } if(opt == 2) { scanf("%d%d", &l, &r); ll ans = query(1, n, 1, l, r); printf("%lld\n", ans); } } return 0; }