这里会显示出您选择的修订版和当前版本之间的差别。
| 两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
|
2020-2021:teams:namespace:2020洛谷多校day1 [2020/05/10 23:50] great_designer [题面] |
2020-2021:teams:namespace:2020洛谷多校day1 [2020/05/18 18:07] (当前版本) great_designer |
||
|---|---|---|---|
| 行 47: | 行 47: | ||
| 输出:到有1 000 000 000块钱的时候的日期 | 输出:到有1 000 000 000块钱的时候的日期 | ||
| + | |||
| + | ====样例==== | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 2 | ||
| + | |||
| + | 999999999 2020 2 29 | ||
| + | |||
| + | 114514 1919 8 10 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 2020 3 1 | ||
| + | |||
| + | 2042 1 15 | ||
| ====解答==== | ====解答==== | ||
| 行 209: | 行 225: | ||
| 如果有多个答案,请打印任何答案。 | 如果有多个答案,请打印任何答案。 | ||
| + | |||
| + | ====样例==== | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 4 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 2 2 | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 6 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 3 3 | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 8 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 3 5 | ||
| + | |||
| + | 第三个输出5 3也是正确的。 | ||
| ====解答==== | ====解答==== | ||
| 行 295: | 行 339: | ||
| </code> | </code> | ||
| - | |||
| - | 以下四题是未AC的题目。接下来几天看看题解。(待施工) | ||
| =====A===== | =====A===== | ||
| 行 315: | 行 357: | ||
| 输出将在图形上以单行方式发生的爆炸数。 | 输出将在图形上以单行方式发生的爆炸数。 | ||
| + | |||
| + | ====样例==== | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 2 3 | ||
| + | |||
| + | 1 1 1 | ||
| + | |||
| + | 1 2 1 | ||
| + | |||
| + | 1 2 1 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 2 | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 4 5 | ||
| + | |||
| + | 1 2 1 | ||
| + | |||
| + | 1 3 1 | ||
| + | |||
| + | 2 3 1 | ||
| + | |||
| + | 2 4 1 | ||
| + | |||
| + | 3 4 1 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 2 | ||
| + | |||
| + | ====题解==== | ||
| + | |||
| + | 我一开始直觉是统计圈的个数(破圈),但后来发现当同时到达顶点的时候,只统计一次爆炸而不是多次,最后只好打算模拟bfs…… | ||
| + | |||
| + | 题解放进了这个页面:[[广度优先搜索_bfs_与标数最短路_dijkstra]] | ||
| =====C===== | =====C===== | ||
| 行 335: | 行 417: | ||
| 输出应答模块998244353。 | 输出应答模块998244353。 | ||
| + | |||
| + | ====样例==== | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 1 2 10 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 5 | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 2 7 16 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 2 | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 16 7 10 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 12866400 | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 16 7 16 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 575218836 | ||
| + | |||
| + | ====题解==== | ||
| + | |||
| + | 这是本套题最难的题目。难点在于细节特别多。 | ||
| + | |||
| + | 原题题解如下: | ||
| + | |||
| + | 首先考虑p 与k 不互素的情况。这种情况下,整除只与最后一位有关,且有$$\frac{k}{p}-1$$种取法,其余位任取。注意k = p 时答案为[n = 1],可能会导致部分没有特判的程序挂掉。 | ||
| + | |||
| + | 现在考虑(p, k) = 1 的情况。考虑暴力:dpi,j 表示前i 位和后i 位填好了,其余位取0 时mod p = j的方案数。更新一位的复杂度是O(kp) 的,总复杂度是O(nkp) 的。 | ||
| + | |||
| + | 考虑优化,由费马小定理,ki mod p 存在长度为p − 1 循环节,因此$$k^{i} + k^{n−i−1}\quad mod \ p$$ 也有长度为p − 1 的循环节。按p − 1 分块后,每块的贡献是相同的,而块的背包合并可以通过类似多项式乘法的循环卷积来实现,因此就可以快速幂了。 | ||
| + | |||
| + | 预处理一个块和处理边缘的零散部分的复杂度是O(kp2), 一次块的暴力卷积是O(p2) 的,因此总复杂度为O(kp2 + p2(log n − log p))。 | ||
| + | |||
| + | 标程使用vector 实现,不开O2 也只跑了一秒,应该是不卡常的。 | ||
| + | |||
| + | 以上。 | ||
| + | |||
| + | 好。我可以明确地宣布,到“快速幂”之前的部分还是能看懂的。之后就不知道怎么个递推法了。 | ||
| + | |||
| + | 标程代码如下: | ||
| + | |||
| + | <code C++> | ||
| + | |||
| + | #include<iostream> | ||
| + | #include<vector> | ||
| + | |||
| + | using namespace std; | ||
| + | |||
| + | long long MOD=998244353; | ||
| + | |||
| + | long long power(long long first, long long second, long long z) | ||
| + | { | ||
| + | long long ret = 1; | ||
| + | for(first %= z; second; second >>= 1) | ||
| + | { | ||
| + | if(second & 1) | ||
| + | { | ||
| + | ret = ret * first % z; | ||
| + | } | ||
| + | first = first * first % z; | ||
| + | } | ||
| + | return ret; | ||
| + | } | ||
| + | |||
| + | long long n; | ||
| + | int p, K; | ||
| + | |||
| + | void init(vector <int> & a) | ||
| + | { | ||
| + | a.clear(); | ||
| + | a.resize(p); | ||
| + | a[0] = 1; | ||
| + | } | ||
| + | |||
| + | void upd(vector <int> &a, long long b, int st = 0) | ||
| + | { | ||
| + | int first; | ||
| + | if (b == n - b - 1) | ||
| + | { | ||
| + | first = int(power(K, b, p)) % p; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | first = int(power(K, b, p) + power(K, n - b - 1, p)) % p; | ||
| + | } | ||
| + | vector <int> c; | ||
| + | c.resize(p); | ||
| + | int i; | ||
| + | for(i = st; i < K; i++) | ||
| + | { | ||
| + | int j; | ||
| + | for(j = 0; j < p; j++) | ||
| + | { | ||
| + | (c[(j + i * first) % p] += a[j]) %= MOD; | ||
| + | } | ||
| + | } | ||
| + | swap(a, c); | ||
| + | } | ||
| + | |||
| + | void mul(vector <int> &a, vector <int> &b) | ||
| + | { | ||
| + | vector <int> c; | ||
| + | c.resize(p); | ||
| + | int i; | ||
| + | for(i = 0; i < p; i++) | ||
| + | { | ||
| + | int j; | ||
| + | for(j = 0; j < p; j++) | ||
| + | { | ||
| + | int first = (i + j) % p; | ||
| + | c[first] = int((c[first] + (long long)a[i] * b[j]) % MOD); | ||
| + | } | ||
| + | } | ||
| + | swap(a, c); | ||
| + | } | ||
| + | |||
| + | void power(vector <int> &a, long long b) | ||
| + | { | ||
| + | vector <int> ret; | ||
| + | init (ret); | ||
| + | for(;b;b>>=1) | ||
| + | { | ||
| + | if(b & 1) | ||
| + | { | ||
| + | mul(ret, a); | ||
| + | } | ||
| + | mul(a, a); | ||
| + | } | ||
| + | swap(a, ret); | ||
| + | } | ||
| + | |||
| + | vector <int> ans, tr; | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | scanf("%lld%d%d", &n, &p, &K); | ||
| + | if(n == 1) | ||
| + | { | ||
| + | int aa = 0; | ||
| + | int i; | ||
| + | for(i = 0; i < K; i++) | ||
| + | { | ||
| + | if (i % p == 0) | ||
| + | { | ||
| + | aa ++; | ||
| + | } | ||
| + | } | ||
| + | cout << aa << endl; | ||
| + | return 0; | ||
| + | } | ||
| + | long long sz = n / 2 - 1; | ||
| + | if (K % p == 0) | ||
| + | { | ||
| + | cout << (K / p - 1) * power(K, sz + (n & 1), MOD) % MOD << endl; | ||
| + | return 0; | ||
| + | } | ||
| + | init(ans); | ||
| + | init(tr); | ||
| + | long long tot = sz / (p - 1); | ||
| + | if(tot) | ||
| + | { | ||
| + | int i; | ||
| + | for(i = 2; i <= p; i++) | ||
| + | { | ||
| + | upd(tr, i - 1); | ||
| + | } | ||
| + | power(tr, tot); | ||
| + | mul(ans, tr); | ||
| + | } | ||
| + | upd(ans, 0, 1); | ||
| + | long long i; | ||
| + | for(i = 2 + tot * (p - 1); i <= (n + 1) / 2; i++) | ||
| + | { | ||
| + | upd(ans, i - 1); | ||
| + | } | ||
| + | printf("%d\n", ans[0]); | ||
| + | } | ||
| + | |||
| + | </code> | ||
| + | |||
| + | 总之这是道值得好好研究的题目。 | ||
| =====D===== | =====D===== | ||
| 行 355: | 行 634: | ||
| 对于每个测试用例,在单独的一行上打印一个表示第K个最小不公平价格的整数。 | 对于每个测试用例,在单独的一行上打印一个表示第K个最小不公平价格的整数。 | ||
| + | |||
| + | ====样例==== | ||
| + | |||
| + | 输入 | ||
| + | |||
| + | 2 | ||
| + | |||
| + | 2 3 1 | ||
| + | |||
| + | 314159 233333 123456789 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 1 | ||
| + | |||
| + | 123570404 | ||
| + | |||
| + | ====题解==== | ||
| + | |||
| + | 本题找到了“逆变换”结论:给定值,判断是第几个。因此最终就是一个二分查找。 | ||
| + | |||
| + | 我想新开一个页面来讲解本题。题解也先放进去了。 | ||
| + | |||
| + | [[裴蜀定理与一次不定方程]] | ||
| + | |||
| =====H===== | =====H===== | ||
| 行 375: | 行 679: | ||
| 输出n行,在第i行打印一个整数,表示子树i的危险分数。 | 输出n行,在第i行打印一个整数,表示子树i的危险分数。 | ||
| + | ====样例==== | ||
| + | 输入 | ||
| + | |||
| + | 5 | ||
| + | |||
| + | 1 2 1 1 2 | ||
| + | |||
| + | 1 2 | ||
| + | |||
| + | 2 3 | ||
| + | |||
| + | 2 4 | ||
| + | |||
| + | 5 1 | ||
| + | |||
| + | 输出 | ||
| + | |||
| + | 8 2 0 0 0 | ||
| + | |||
| + | ====题解==== | ||
| + | |||
| + | 这个题解就很高端了…… | ||
| + | |||
| + | 采用支持合并的数据结构,下标维护标号,信息维护深度总和与点数,在每个点合并子树信息并维护答案。合并的两端的某个颜色的信息分别为(dep1, cnt1), (dep2, cnt2),当前点深度为d,则合并时产生贡献: | ||
| + | |||
| + | $$dep_1cnt_2 + dep_2cnt_1 − 2d \ cnt_1cnt_2$$ | ||
| + | |||
| + | 采用线段树合并等的时间复杂度为O(n log n),采用启发式合并的set(map) 也能够以O(n log2 n) 的复杂度通过。 | ||
| + | |||
| + | 给了两份代码: | ||
| + | |||
| + | <code C++> | ||
| + | |||
| + | #include<stdio.h> | ||
| + | #include<vector> | ||
| + | |||
| + | using namespace std; | ||
| + | |||
| + | struct Node | ||
| + | { | ||
| + | long long dep; | ||
| + | int l, r, cnt; | ||
| + | }; | ||
| + | |||
| + | struct Node t[201111 * 19]; | ||
| + | |||
| + | vector <int> E[201111]; | ||
| + | |||
| + | int n, tcnt; | ||
| + | int a[201111], rt[201111], dep[201111]; | ||
| + | |||
| + | long long sc[201111], delta; | ||
| + | int curdep; | ||
| + | |||
| + | int Merge(int x, int y, int l, int r) | ||
| + | { | ||
| + | if (!y) return x; | ||
| + | if (!x) return y; | ||
| + | if (l == r) | ||
| + | { | ||
| + | delta += t[x].dep * t[y].cnt + t[y].dep * t[x].cnt - 2ll * curdep * t[x].cnt * t[y].cnt; | ||
| + | t[x].dep += t[y].dep; | ||
| + | t[x].cnt += t[y].cnt; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | int mid = (l + r) / 2; | ||
| + | t[x].l = Merge(t[x].l, t[y].l, l, mid); | ||
| + | t[x].r = Merge(t[x].r, t[y].r, mid + 1, r); | ||
| + | } | ||
| + | return x; | ||
| + | } | ||
| + | |||
| + | int init(int p, int l, int r) | ||
| + | { | ||
| + | int x = ++tcnt; | ||
| + | if (l < r) | ||
| + | { | ||
| + | int mid = (l + r) / 2; | ||
| + | if (p <= mid) t[x].l = init(p, l, mid); | ||
| + | else t[x].r = init(p, mid + 1, r); | ||
| + | } | ||
| + | else t[x].dep = curdep, t[x].cnt = 1; | ||
| + | return x; | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | void dfs(int x, int fa) | ||
| + | { | ||
| + | curdep = dep[x]; | ||
| + | rt[x] = init(a[x], 1, n); | ||
| + | for (auto v : E[x]) | ||
| + | { | ||
| + | if (v != fa) | ||
| + | { | ||
| + | dep[v] = dep[x] + 1; | ||
| + | dfs(v, x); | ||
| + | sc[x] += sc[v]; | ||
| + | delta = 0; | ||
| + | curdep = dep[x]; | ||
| + | rt[x] = Merge(rt[x], rt[v], 1, n); | ||
| + | sc[x] += delta; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | scanf("%d", &n); | ||
| + | int i; | ||
| + | for(i = 1; i <= n; i++) | ||
| + | { | ||
| + | scanf("%d", a + i); | ||
| + | } | ||
| + | for(i = 1; i < n; i++) | ||
| + | { | ||
| + | int u, v; | ||
| + | scanf("%d%d", &u, &v); | ||
| + | E[u].push_back(v); | ||
| + | E[v].push_back(u); | ||
| + | } | ||
| + | dfs(1, -1); | ||
| + | for(i = 1; i <= n; i++) | ||
| + | { | ||
| + | printf("%lld ", sc[i]); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </code> | ||
| + | |||
| + | <code C++> | ||
| + | |||
| + | #include<stdio.h> | ||
| + | #include<vector> | ||
| + | #include<map> | ||
| + | |||
| + | using namespace std; | ||
| + | |||
| + | vector <int> E[101111]; | ||
| + | |||
| + | int n; | ||
| + | int a[101111], dep[101111]; | ||
| + | |||
| + | map<int, pair<long long, int> > rt[101111]; | ||
| + | |||
| + | long long sc[101111], delta; | ||
| + | int curdep; | ||
| + | |||
| + | void Merge(map<int, pair<long long, int> >& a, map<int, pair<long long, int> >& b) | ||
| + | { | ||
| + | if (a.size() < b.size()) swap(a, b); | ||
| + | for (auto& v : b) | ||
| + | { | ||
| + | int col = v.first; | ||
| + | auto it = a.find(col); | ||
| + | if (it != a.end()) | ||
| + | { | ||
| + | long long d1 = it->second.first, c1 = it->second.second; | ||
| + | long long d2 = v.second.first, c2 = v.second.second; | ||
| + | delta += d1 * c2 + d2 * c1 - 2LL* curdep * c1 * c2; | ||
| + | it->second.first += d2; | ||
| + | it->second.second += int(c2); | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | a.insert(v); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void init(map<int, pair<long long, int>>& r, int p) | ||
| + | { | ||
| + | r[p] = { curdep, 1 }; | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | void dfs(int x, int fa) | ||
| + | { | ||
| + | curdep = dep[x]; | ||
| + | init(rt[x], a[x]); | ||
| + | for (auto v : E[x]) | ||
| + | { | ||
| + | if (v != fa) | ||
| + | { | ||
| + | dep[v] = dep[x] + 1; | ||
| + | dfs(v, x); | ||
| + | sc[x] += sc[v]; | ||
| + | delta = 0; | ||
| + | curdep = dep[x]; | ||
| + | Merge(rt[x], rt[v]); | ||
| + | sc[x] += delta; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | scanf("%d", &n); | ||
| + | int i; | ||
| + | for(i = 1; i <= n; i++) | ||
| + | { | ||
| + | scanf("%d", a + i); | ||
| + | } | ||
| + | for(i = 1; i < n; i++) | ||
| + | { | ||
| + | int u, v; | ||
| + | scanf("%d%d", &u, &v); | ||
| + | E[u].push_back(v); | ||
| + | E[v].push_back(u); | ||
| + | } | ||
| + | dfs(1, -1); | ||
| + | for(i = 1; i <= n; i++) | ||
| + | { | ||
| + | printf("%lld ", sc[i]); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </code> | ||