题目链接 Codeforces Educational Round 33
Problem A
按照题目模拟,中间发现不对就直接输出NO。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; int a, b, c, n; int main(){ a = 1, b = 2, c = 3; scanf("%d", &n); rep(i, 1, n){ int x; scanf("%d", &x); if (x != a && x != b) return 0 * puts("NO"); if (x == a) swap(b, c); else swap(a, c); } puts("YES"); return 0; }
Problem B
打表然后塞到set里面,然后查找一下。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; int c[20]; int a[100010]; int n; int cnt, et; set <int> s; int main(){ rep(i, 1, 10){ int a = (1 << i) - 1; int b = (1 << (i - 1)); s.insert(a * b); } rep(i, 1, et) printf("%d ", c[i]); scanf("%d", &n); rep(i, 1, n) if (n % i == 0) a[++cnt] = i; dec(i, cnt, 1) if (s.count(a[i])) return 0 * printf("%d ", a[i]);; return 0; }
Problem C
在每个连通块里面找个权值最小的然后加起来即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 1e6 + 10; LL a[N]; LL now; LL ans = 0; int vis[N]; vector <int> v[N]; int n, m; void dfs(int x){ vis[x] = 1; now = min(now, a[x]); for (auto u : v[x]){ if (!vis[u]) dfs(u); } } int main(){ scanf("%d%d", &n, &m); rep(i, 1, n) scanf("%lld", a + i); rep(i, 1, m){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } rep(i, 1, n) if (!vis[i]){ now = 1e10; dfs(i); ans += now; } printf("%lld ", ans); return 0; }
Problem D
考虑每一天的时候,记录min和max,分别表示钱的下限值和上限值。
如果min都超过d了那肯定不行了,输出-1。
check的时候根据mx是否非负来决定是否更新答案。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) int n, d; int x; int mi = 0, mx = 0; int ans; int main(){ scanf("%d%d", &n, &d); rep(i, 1, n){ scanf("%d", &x); if (x){ mi += x, mx += x; if (mi > d) return 0 * puts("-1"); mx = min(mx, d); } else{ if (mx >= 0) mi = max(mi, 0); else ++ans, mx = d, mi = 0; } } printf("%d ", ans); return 0; }
Problem E
首先来个预处理,把所有的数的质因子以及指数求出来。
然后对于每一个质因子c,找到他的指数d。
转化成盒子里面放小球的问题。
(盒子不同,小球相同,允许空盒子的情况)
那么当前质因子c对答案的贡献即为$C(y + d - 1, d)$
由于各质因子之间是独立的,所以直接相乘即可。
最后还有-1的情况,对整个ans乘上$2^{y - 1}$即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; typedef pair <int, int> PII; const int N = 2e6 + 10; const int mod = 1e9 + 7; int fac[N]; int c[N]; int val[N]; int ret, q, x, y; int inv[N]; vector <PII> pri[N]; inline int Pow(int a, int b, int mod){ int ret = 1; for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod; return ret; } inline int C(int n, int k){ return 1ll * fac[n] * inv[k] % mod * inv[n - k] % mod; } void init(){ fac[0] = 1; rep(i, 1, 2e6 + 3) fac[i] = 1ll * fac[i - 1] * i % mod; rep(i, 0, 2e6 + 3) inv[i] = Pow(fac[i], mod - 2, mod); rep(i, 1, 1e6 + 3) val[i] = i; rep(i, 2, 1e6 + 3) if (!c[i]){ for (int j = i * 2; j <= 1e6 + 3; j += i){ c[j] = 1; int cnt = 0; while (val[j] % i == 0) val[j] /= i, ++cnt; pri[j].push_back(MP(i, cnt)); } } rep(i, 2, 1e6 + 3) if (val[i] > 1) pri[i].push_back(MP(i, 1)); } int main(){ init(); scanf("%d", &q); while (q--){ int x, y; scanf("%d%d", &x, &y); ret = Pow(2, y - 1, mod); for (auto u : pri[x]){ int d = u.se; ret = 1ll * ret * C(y + d - 1, d) % mod; } printf("%d ", ret); } return 0; }
Problem F
对于每一个结点,维护以他为根的子树中深度在[l, r]范围内的所有点的权值的最小值。
一开始每个点在空树的基础上在自己这个深度插入自己的权值。
每个点的插入复杂度为$O(logn)$,因为要开$logn$棵线段树。
然后dfs一遍,做$n$次线段树合并即可。
查询的时候对询问的距离$d$加上当前结点的深度$deep$,这样就构成了一个询问区间$[1, d + deep]$。
为什么左端点是$1$呢,因为当前结点代表的线段树在$[1, deep - 1]$内都没有信息,那么$[1, d + deep]$就可以等效题目的询问区间。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 1e5 + 10; const int M = 2e7 + 10; int father[N], deep[N]; int n, r; vector <int> v[N]; int a[N]; int t[M], ls[M], rs[M]; int tot = 0; int val[M]; int m; int ans; void dfs(int x, int fa, int dep){ deep[x] = dep; father[x] = fa; for (auto u : v[x]){ if (u == fa) continue; dfs(u, x, dep + 1); } } int ins(int x, int a, int b, int c, int p){ int y = ++tot; val[y] = min(val[x], p); if (a == b) return y; int mid = (a + b) >> 1; if (c <= mid) ls[y] = ins(ls[x], a, mid, c, p), rs[y] = rs[x]; else ls[y] = ls[x], rs[y] = ins(rs[x], mid + 1, b, c, p); return y; } int ask(int x, int a, int b, int d){ if (b <= d) return val[x]; int mid = (a + b) >> 1, t = ask(ls[x], a, mid, d); if (d > mid) t = min(t, ask(rs[x], mid + 1, b, d)); return t; } int merge1(int x, int y, int a, int b){ if (!x || !y) return x + y; int z = ++tot; val[z] = min(val[x], val[y]); if (a == b) return z; int mid = (a + b) >> 1; ls[z] = merge1(ls[x], ls[y], a, mid); rs[z] = merge1(rs[x], rs[y], mid + 1, b); return z; } void work(int x, int fa){ for (auto u : v[x]){ if (u == fa) continue; work(u, x); } for (auto u : v[x]){ if (u == fa) continue; t[x] = merge1(t[x], t[u], 1, n); } } int main(){ scanf("%d%d", &n, &r); rep(i, 1, n) scanf("%d", a + i); rep(i, 0, 2e7) val[i] = 2147000000; rep(i, 2, n){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } dfs(r, 0, 1); rep(i, 1, n) t[i] = ins(0, 1, n, deep[i], a[i]); work(r, 0); ans = 0; scanf("%d", &m); while (m--){ int x, y; scanf("%d%d", &x, &y); x = ((x + ans) % n) + 1; y = ((y + ans) % n); y += deep[x]; if (y > n) y = n; printf("%d ", ans = ask(t[x], 1, n, y)); } return 0; }