NOIP第二階段總結
阿新 • • 發佈:2020-11-23
聯賽模擬測試37
階段排名 27
A 簡單題
-
考場上想出a+b+c是定值且q沒啥用,但還是沒找到規律
-
觀察式子,將A和B加起來就可以把P消掉
-
然後每次變化就是A+B和C兩個數中大的減小的,小的變兩倍
-
如果C小,C變兩倍,
-
如果C大,\(C=C-(A+B)=C-((A+B+C)-C)=2C-(A+B+C)\),C變兩倍減去和,和是定值,答案就轉換成\(C*2^k\mod (A+B+C)\)
Show Code
#include <cstdio> int read(int x = 0, int f = 1, char c = getchar()) { for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0'; return x * f; } int Pow(int a, int k, int M, int ans = 1) { for (; k; k >>= 1, a = 1LL * a * a % M) if (k & 1) ans = 1LL * ans * a % M; return ans; } int main() { freopen("easy.in", "r", stdin); freopen("easy.out", "w", stdout); int T = read(); while (T--) { int x = read() + read(), y = read(), k = read(); x += y; printf("%lld\n", 1LL * y * Pow(2, k, x) % x); } return 0; }
B 鬥地主
-
我記得學長講過,但忘了怎麼寫了,本來想寫60分二分圖,然後懶得寫,就寫了個40分暴搜,有個地方寫掛了就只剩20了
-
每張牌上正面的數向背面的數建雙向邊,一個聯通塊如果是樹就會有一個點不能選,那麼一個區間同時包含這個聯通塊的最大值和最小值,就不能組成
-
可以維護一個ans[i]表示從i開始最大能到幾,雙指標就可以O(n)預處理出這個陣列,每次查詢就可以做到O(1)了
Show Code
#include <cstdio> const int N = 2e5 + 5; int read(int x = 0, int f = 1, char c = getchar()) { for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0'; return x * f; } int n, m, f[N], s[N], b[N], ans[N]; int Find(int x) { return x == f[x] ? x : (f[x] = Find(f[x])); } int main() { freopen("playingcard.in", "r", stdin); freopen("playingcard.out", "w", stdout); n = read(); m = read(); for (int i = 1; i <= n; ++i) f[i] = i; while (m--) { int x = Find(read()), y = Find(read()); s[x]++; if (x == y) continue; f[y] = x; s[x] += s[y]; } for (int i = 1, j = 1; i <= n; ++i) { for (int x; j <= n && b[x=Find(j)] < s[x]; ++j) b[x]++; ans[i] = j - 1; b[Find(i)]--; } m = read(); while (m--) { int x = read(); puts(read() <= ans[x] ? "Yes" : "No"); } return 0; }
C 變化的樹
-
對於x子樹上的點y,它增加的值就是w-k(dep[y]-dep[x]) = w+kdep[x]-kdep[y],
-
對於每個點維護w+kdep[x]的和sw[i]和k的和sk[i],查詢的時候就是sw[x]-dep[x]sk[x]
-
那就拿一個支援區間加,單點查的資料結構,其實樹狀陣列就可以,然而我考場寫的大常數線段樹
Show Code
#include <cstdio> const int N = 3e5 + 5, M = 1e9 + 7; int read(int x = 0, int f = 1, char c = getchar()) { for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0'; return x * f; } struct Edge { int next, t; }e[N]; int head[N], edc; void Add(int x, int y) { e[++edc] = (Edge) {head[x], y}; head[x] = edc; } int n, dep[N], dfc, dfn[N], a[N], siz[N], tw[N], tk[N]; void Dfs(int x, int fa) { siz[x] = 1; dep[x] = dep[fa] + 1; dfn[x] = ++dfc; a[dfc] = x; for (int i = head[x]; i; i = e[i].next) { int y = e[i].t; Dfs(y, x); siz[x] += siz[y]; } } void Add(int x, int w, int k) { for (; x <= n; x += x & -x) { if ((tw[x] += w) >= M) tw[x] -= M; if ((tk[x] += k) >= M) tk[x] -= M; } } int Ask(int x, bool g, int s = 0) { for (; x; x -= x & -x) if ((s += (g ? tw[x] : tk[x])) >= M) s -= M; return s; } int main() { freopen("change.in", "r", stdin); freopen("change.out", "w", stdout); n = read(); for (int i = 2; i <= n; ++i) Add(read(), i); Dfs(1, 0); int m = read(); while (m--) { int od = read(), x = read(); if (od == 1) { int w = read(), k = read(); w = (w + 1LL * dep[x] * k) % M; Add(dfn[x], w, k); Add(dfn[x] + siz[x], -w, -k); } else printf("%lld\n", (Ask(dfn[x], 1) - 1LL * dep[x] * Ask(dfn[x], 0) % M + M) % M); } return 0; }
D 鍊金術 (Unaccepted)
- 神仙題爆0
Show Code