题目链接 Problems
HDOJ上的题目顺序可能和现场比赛的题目顺序不一样,
我这里的是按照HDOJ的题目顺序来写的。
Problem 1001
签到
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) typedef long long LL; LL n, f[31]; int ans; int main(){ f[1] = 1LL; for (LL i = 2; i <= 15; ++i){ f[i] = 1LL; rep(j, 1, i) f[i] *= i; } while (~scanf("%lld", &n)){ ans = 0; rep(i, 1, 15) if (f[i] <= n) ans = max(ans, i); printf("%d ", ans); } return 0; }
Problem 1002
这道题的话,其实一个点上是可以有多种颜色的
因为最多只有51种颜色,所以我们维护51棵线段树即可。
我们对y坐标建立线段树,对于每个y,我们只需要知道最小的x在哪里即可。
因为他的询问的x坐标下界总是1,那么我们只要看看y1到y2的最小值是否小于等于给定的x即可。
询问的时候做51次子询问就可以了。
#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) typedef long long LL; const int N = 2e6 + 10; int X, c, d, x, y, op, ans, ret, cnt; int root[53]; int l[N], r[N], v[N]; void update(int &i, int L, int R, int x, int val){ if (i == 0){ i = ++cnt; v[i] = val; } v[i] = min(v[i], val); if (L == R) return; int mid = (L + R) >> 1; if (x <= mid) update(l[i], L, mid, x, val); else update(r[i], mid + 1, R, x, val); } void query(int i, int L, int R){ if (ret || i == 0) return; if (c <= L && R <= d){ if (v[i] <= X) ret = 1; return; } int mid = (L + R) >> 1; if (c <= mid) query(l[i], L, mid); if (d > mid) query(r[i], mid + 1, R); } int main(){ while (true){ scanf("%d", &op); if (op == 3) break; if (op == 0){ rep(i, 1, cnt) l[i] = r[i] = 0; memset(root, 0, sizeof root); cnt = 0; } if (op == 1){ scanf("%d%d%d", &x, &y, &c); update(root[c], 1, 1000000, y, x); } if (op == 2){ scanf("%d%d%d", &X, &c, &d); ans = 0; rep(i, 0, 50){ ret = 0; query(root[i], 1, 1000000); ans += ret; } printf("%d ", ans); } } return 0; }
Problem 1003
我们对于每一条边,找到所有包含这条边的三元环,个数计为x
然后这对答案的贡献就是$C_{x}^{2}$
判断两点之间是否有边的时候要手写哈希才能过
#include <bits/stdc++.h> const int N = 2e5 + 10; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) namespace Hashmap{ const int P = 1000007, seed = 2333; int u[N << 2], v[N << 2], nt[N << 2]; int head[P], inum; inline void init(){ inum = 0; memset(u, 0, sizeof u); memset(v, 0, sizeof v); memset(nt, 0, sizeof nt); memset(head, 0, sizeof head); } inline void add(int _u, int _v){ int t = (_u * seed + _v) % P; u[++inum] = _u, v[inum] = _v, nt[inum] = head[t], head[t] = inum; } inline bool query(int _u, int _v){ int t = (_u * seed + _v) % P; for (int p = head[t]; p; p = nt[p]) if (u[p] == _u && v[p] == _v) return 1; return 0; } } using namespace std; using namespace Hashmap; typedef long long LL; vector<int> a[N]; struct ss{ int x, y; } e[N]; int n, m; int main(){ while (~scanf("%d%d",&n, &m)){ init(); rep(i, 1, n) a[i].clear(); rep(i, 1, m){ int x, y; scanf("%d%d", &x, &y); e[i].x = x; e[i].y = y; a[x].push_back(y); a[y].push_back(x); add(x, y); add(y, x); } LL ans = 0; rep(i, 1, m){ int x = e[i].x, y = e[i].y; if (a[e[i].y].size() < a[e[i].x].size()) swap(x, y); LL tot = 0; for (auto u: a[x]) if (query(u, y)) tot++; ans += tot * (tot - 1) / 2; } printf("%lld ", ans); } return 0; }
Problem 1004
这题规律找了半天……
$f[n] = f[n - 1] + 5f[n - 2] + f[n - 3] - f[n - 4]$
然后矩阵加速下就可以了
#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 LL mod = 1e9 + 7; struct Matrix{ LL arr[6][6]; } f, unit, a; LL m, k; int n; Matrix Add(Matrix a, Matrix b){ Matrix c; rep(i, 1, n) rep(j, 1, n){ c.arr[i][j] = (a.arr[i][j] + b.arr[i][j]) % mod; } return c; } Matrix Mul(Matrix a, Matrix b){ Matrix c; rep(i, 1, n) rep(j, 1, n){ c.arr[i][j] = 0; rep(k, 1, n) (c.arr[i][j] += (a.arr[i][k] * b.arr[k][j] % mod)) %= mod; } return c; } Matrix Pow(Matrix a, LL k){ Matrix ret(unit); for (; k; k >>= 1, a = Mul(a, a)) if (k & 1) ret = Mul(ret, a); return ret; } int main(){ n = 4; memset(f.arr, 0, sizeof f.arr); memset(a.arr, 0, sizeof a.arr); memset(unit.arr, 0, sizeof unit.arr); rep(i, 1, n) unit.arr[i][i] = 1; f.arr[1][1] = 1; f.arr[1][2] = 5; f.arr[1][3] = 1; f.arr[1][4] = 1000000006; f.arr[2][1] = 1; f.arr[3][2] = 1; f.arr[4][3] = 1; a.arr[1][1] = 36; a.arr[2][1] = 11; a.arr[3][1] = 5; a.arr[4][1] = 1; while (~scanf("%lld", &m)){ if (m == 1LL){ puts("1"); continue;} if (m == 2LL){ puts("5"); continue;} if (m == 3LL){ puts("11"); continue;} if (m == 4LL){ puts("36"); continue;} if (m == 5LL){ puts("95"); continue;} k = m - 4; Matrix b = Pow(f, k); Matrix c = Mul(b, a); printf("%lld ", c.arr[1][1]); } return 0; }
Problem 1010
这道题的话先转DFS序,然后求出以每个点为根的子树的对应区间,
于是就转化成了求区间里选一个数和x异或后的最大值。
可持久化trie即可。
#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) typedef long long LL; const int N = 1e5 + 10; const int M = 1e7 + 10; int n, m, tot = 0; int rt[N], id[M], t[M][2]; int l, r, x; int a[N], c[N], L[N], R[N], g[N]; int ti; int u; vector <int> v[N]; inline void insert(int pre, int x, int k){ int now = rt[k] = ++tot; id[tot] = k; dec(i, 30, 0){ int j = (x >> i) & 1; t[now][j ^ 1] = t[pre][j ^ 1]; t[now][j] = ++tot; id[tot] = k; now = t[now][j]; pre = t[pre][j]; } } inline int query(int l, int r, int x){ int ans = 0, tmp = rt[r]; dec(i, 30, 0){ if (id[tmp] < l) break; int j = ((x >> i) & 1) ^ 1; if (id[t[tmp][j]] >= l) ans |= (1 << i); else j ^= 1; tmp = t[tmp][j]; } return ans; } void dfs(int x){ L[x] = ++ti; g[ti] = a[x]; for (auto u : v[x]){ dfs(u); } R[x] = ti; } int main(){ while (~scanf("%d%d", &n, &m)){ memset(id, 0, sizeof id); memset(rt, 0, sizeof rt); memset(t, 0, sizeof t); memset(L, 0, sizeof L); memset(R, 0, sizeof R); tot = 0; ti = 0; rep(i, 0, n + 1) v[i].clear(); rep(i, 1, n) scanf("%d", a + i); rep(i, 2, n){ scanf("%d", &x); v[x].push_back(i); } dfs(1); id[0] = -1; insert(0, 0, 0); rep(i, 1, n) insert(rt[i - 1], g[i], i); rep(i, 1, m){ scanf("%d%d", &u, &x); printf("%d ", query(L[u], R[u], x)); } } return 0; }