Problem A
直接暴力,当然我O(n)过的。
#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 ans = 0; char s[205]; int a[205], b[205]; int n; int main(){ scanf("%s", s + 1); n = strlen(s + 1); rep(i, 1, n) if (s[i] == 'Q') a[i] = a[i - 1] + 1; else a[i] = a[i - 1]; dec(i, n, 1) if (s[i] == 'Q') b[i] = b[i + 1] + 1; else b[i] = b[i + 1]; rep(i, 1, n) if (s[i] == 'A') ans += a[i] * b[i]; printf("%d ", ans); return 0; }
Problem B
打表找规律……当k为-1且n和m奇偶性不同的时候答案为0。
#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; LL n, m; int k; inline LL Pow(LL a, LL b, LL Mod){ LL ret(1); for (; b; b >>= 1, (a *= a) %= Mod) if (b & 1) (ret *= a) %= Mod; return ret; } int main(){ scanf("%lld%lld%d", &n, &m, &k); if (k == 1){ LL yy = n - 1; LL hh = Pow(2, yy, mod); LL ans = Pow(hh, m - 1, mod); printf("%lld ", ans); } else{ LL tt = n + m; if (tt % 2 == 1) return 0 * puts("0"); if (n % 2 == 1){ LL oo = (n + 1) / 2; LL pp = oo - 1; LL mul = Pow(16, pp, mod); LL mm = m / 2; LL ans = Pow(mul, mm, mod); printf("%lld ", ans); } else{ LL xx = n / 2, yy = m / 2; LL mul = 4 * Pow(16, xx - 1, mod) % mod; LL ff = 2 * Pow(4, xx - 1, mod) % mod; LL ans = ff * Pow(mul, yy - 1, mod) % mod; printf("%lld ", ans); } } return 0; }
Problem C
构造题(赛时被X……)
若最大的那个不能整除所有比他小的数,那么无解
否则就按照s1,s1,s2,s1,s3,s1,s4,s1,...sn,s1这么输出。
关键是想到。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, f) for (int i(a); i <= (f); ++i) #define dec(i, a, f) for (int i(a); i >= (f); --i) #define MP make_pair #define fi first #define se second const int N = 1e6; int n; int c[10100]; int f[N]; int main(){ scanf("%d", &n); rep(i, 1, n) scanf("%d", c + i); rep(i, 2, n) if (c[i] % c[1]) return 0 * puts("-1"); printf("%d ", n << 1); rep(i, 1, n) printf("%d %d ", c[1], c[i]); putchar(10); }
Problem D
暴力存下所有点的所有儿子到他的距离。
因为这是完全二叉树所以内存可以承受。
空间开销$nlogn$,时间复杂度$O(nlog^{2}n)$,如果用归并排序的话那就$O(nlogn)$
然后查询的时候一步步往上爬,把符合条件的答案统计进来。
#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, LL> PII; const int N = 1e6 + 10; int n, m; vector <LL > g[N], s[N]; LL l[N], ans = 0; inline int fa(int x){ return x >> 1;} inline int ls(int x){ return x << 1;} inline int rs(int x){ return x << 1 | 1;} PII calc(int x, LL len){ if (len < 0) return MP(0, 0); if (x > n) return MP(0, 0); int sz = (int)g[x].size(); if (g[x][sz - 1] <= len) return MP(sz, s[x][sz - 1]); int l = 0, r = sz - 1; while (l + 1 < r){ int mid = (l + r) >> 1; if (g[x][mid] <= len) l = mid; else r = mid - 1; } int t; if (g[x][r] <= len) t = r; else t = l; return MP(t + 1, s[x][t]); } void dfs(int x){ if (ls(x) <= n){ dfs(ls(x)); for (auto u : g[ls(x)]) g[x].push_back(l[ls(x)] + u); } if (rs(x) <= n){ dfs(rs(x)); for (auto u : g[rs(x)]) g[x].push_back(l[rs(x)] + u); } g[x].push_back(0); sort(g[x].begin(), g[x].end()); } int main(){ scanf("%d%d", &n, &m); rep(i, 2, n) scanf("%lld", l + i); dfs(1); rep(i, 1, n){ int sz = g[i].size(); s[i].resize(sz + 2); s[0] = g[0]; rep(j, 1, sz - 1) s[i][j] = s[i][j - 1] + g[i][j]; } while (m--){ int x, y; LL len, Len; scanf("%d%lld", &x, &len); Len = len; PII cnt = calc(x, len); ans = 0; ans = cnt.fi * len - cnt.se; y = x, x = fa(x); len -= l[y]; while (x && len >= 0){ if (ls(x) == y){ cnt = calc(rs(x), len - l[rs(x)]); ans += cnt.fi * Len - cnt.se - cnt.fi * (Len - len + l[rs(x)]); } else{ cnt = calc(ls(x), len - l[ls(x)]); ans += cnt.fi * Len - cnt.se - cnt.fi * (Len - len + l[ls(x)]); } ans += len; y = x; x = fa(x); len -= l[y]; } printf("%lld ", ans); } return 0; }
Problem E
预处理出所有强连通分量之后缩点。
缩成的点的权值为该点代表的强连通分量的所有边的价值和(根据题目算出来)
然后就变成了一个DAG,DP一下就可以了。
#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; vector <pair <int, int > > v[N], g[N]; stack <int> stk; LL f[N], val[N]; int n, m; int low[N], dfn[N], sccno[N]; int num = 0, ti = 0; int s; void dfs(int x){ low[x] = dfn[x] = ++ti; stk.push(x); for (auto edge : v[x]){ int u = edge.fi, w = edge.se; if (!low[u]){ dfs(u); dfn[x] = min(dfn[x], dfn[u]); } else if (!sccno[u]) dfn[x] = min(dfn[x], low[u]); } if (dfn[x] == low[x]){ ++num; while (true){ int u = stk.top(); stk.pop(); sccno[u] = num; if (u == x) break; } } } LL work(int x){ if (~f[x]) return f[x]; f[x] = 0; for (auto edge : g[x]) f[x] = max(f[x], work(edge.fi) + edge.se); return f[x] += val[x]; } LL calc(int x){ int rt = sqrt(2 * x); while ((LL)rt * (rt - 1) / 2 <= x) rt++; while ((LL)rt * (rt - 1) / 2 > x) rt--; return (LL)rt * x - (LL)(rt + 1) * rt * (rt - 1) / 6; } int main(){ scanf("%d%d", &n, &m); rep(i, 1, m){ int x, y, z; scanf("%d%d%d", &x, &y, &z); v[x].push_back(MP(y, z)); } scanf("%d", &s); dfs(s); rep(i, 1, n){ for (auto edge : v[i]){ int x = i, y = edge.fi; if (sccno[x] == sccno[y]) val[sccno[x]] += calc(edge.se); else g[sccno[x]].push_back(MP(sccno[y], edge.se)); } } memset(f, -1, sizeof f); printf("%lld ", work(sccno[s])); return 0; }