From faf73ffbcdb3fc7141539631c898a5d9265343e5 Mon Sep 17 00:00:00 2001 From: devilran6 <3470826156@qq.com> Date: Wed, 4 Oct 2023 00:03:10 +0800 Subject: [PATCH] add ACM --- docs/ACM/CF/div2_892.md | 1059 +++++++++++++++++ docs/ACM/CF/div2_893.md | 14 + docs/ACM/CF/div2_899.md | 314 +++++ docs/ACM/CF/edu_155.md | 312 +++++ docs/ACM/ICPC/ccpc2022mianyang.md | 1 + ...33\347\254\254\344\272\214\345\234\272.md" | 36 + .../Math/CF\346\225\260\345\255\246.md" | 305 +++++ .../Math/LG\346\225\260\345\255\246.md" | 17 + docs/about/devilran.md | 8 + docs/index.md | 6 +- mkdocs.yml | 16 +- 11 files changed, 2082 insertions(+), 6 deletions(-) create mode 100644 docs/ACM/CF/div2_892.md create mode 100644 docs/ACM/CF/div2_893.md create mode 100644 docs/ACM/CF/div2_899.md create mode 100644 docs/ACM/CF/edu_155.md create mode 100644 docs/ACM/ICPC/ccpc2022mianyang.md create mode 100644 "docs/ACM/ICPC/icpc\347\275\221\347\273\234\350\265\233\347\254\254\344\272\214\345\234\272.md" create mode 100644 "docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/CF\346\225\260\345\255\246.md" create mode 100644 "docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/LG\346\225\260\345\255\246.md" diff --git a/docs/ACM/CF/div2_892.md b/docs/ACM/CF/div2_892.md new file mode 100644 index 0000000..4252caf --- /dev/null +++ b/docs/ACM/CF/div2_892.md @@ -0,0 +1,1059 @@ +--- +title: CFdiv2_892 +description: ABCDE(F) +categories: + - CF +highlight_shrink: false +abbrlink: 8df7bf3 +date: 2023-08-14 00:00:00 +mathjax: true +copyright_author: devilran +copyright_author_href: +copyright_url: +copyright_info: +--- + +过了abc,卡在了d + +## A United We Stand + +将数组a拆分乘数组b和c,使得满足任意c[i]不是b[j]的因子,b和c中至少存在一个数。 + +如果不能输出-1 + + + +**法一:** + +巧妙构造: + +因为一个大的数不可能是一个小的数的因子,所以我把最大的数(最大的数数量可能有很多个,需要全都放在c里面,因为两个相等的数之间也互为因子)放在c后,其他剩下的数放在b,即构造成功。 + +只有当所有的数都是最大的数(也就是a中所有数都相等),没有数放到b,输出-1 + + + +```cpp +// 赛时代码 +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + vector a(n); + int maxv = 0; + for (int i = 0; i < n; i++) + { + cin >> a[i]; + maxv = max(maxv, a[i]); + } + + sort(a.begin(), a.end()); + if (maxv == a[0]) + { + cout << "-1" << endl; + return; + } + + int pos = 0; + for (int i = 0; i < a.size(); i++) + if (a[i] == maxv) + { + pos = i; + break; + } + + cout << pos << ' ' << n - pos << endl; + for (int i = 0; i < pos; i++) + cout << a[i] << ' '; + cout << endl; + for (int i = pos; i < a.size(); i++) + cout << a[i] << ' '; + cout << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +**法二:** from jiangly + +SCC + +如果 x % y == 0,连接一条 x -> y 的有向边。 + +一个强连通分量里面的点互相之间都满足 x % y == 0,所以一个强连通分量里面的点需要全放在b或者c里面。 + +如果整个图只有一个强连通分量的话,故输出-1 + +如果大于一个的话,因为SCC后按照下标递减的顺序就是拓扑排序 + +所以 bel[i] == 0 => 表示的是只有入度没有出度的那个点 + +除了这个强连通分量里的点都不是这些点的因子,其他点都只可能是这些点的倍数 + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +struct SCC +{ + int n; + vector> adj; + vector stk; + vector dfn, low, bel; + int cur, cnt; + + SCC() {} + SCC(int n) + { + init(n); + } + + void init(int n) + { + this->n = n; + adj.assign(n, {}); + dfn.assign(n, -1); + low.resize(n); + bel.assign(n, -1); + stk.clear(); + cur = cnt = 0; + } + + void addEdge(int u, int v) + { + adj[u].push_back(v); + } + + void dfs(int x) + { + dfn[x] = low[x] = cur++; + stk.push_back(x); + + for (auto y : adj[x]) + { + if (dfn[y] == -1) + { + dfs(y); + low[x] = min(low[x], low[y]); + } + else if (bel[y] == -1) + { + low[x] = min(low[x], dfn[y]); + } + } + + if (dfn[x] == low[x]) + { + int y; + do + { + y = stk.back(); + bel[y] = cnt; + stk.pop_back(); + } while (y != x); + cnt++; + } + } + + vector work() + { + for (int i = 0; i < n; i++) + { + if (dfn[i] == -1) + { + dfs(i); + } + } + return bel; + } +}; + +void solve() +{ + int n; + cin >> n; + + SCC g(n); + vector a(n); + + for (int i = 0; i < n; i++) + cin >> a[i]; + + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + if (a[i] % a[j] == 0) + g.addEdge(i, j); + + auto bel = g.work(); + if (bel == vector(n, 0)) + { + cout << -1 << endl; + return; + } + + vector b, c; + for (int i = 0; i < n; i++) + { + if (bel[i] == 0) + b.push_back(i); + else + c.push_back(i); + } + + cout << b.size() << ' ' << c.size() << endl; + + for(auto i : b) + cout << a[i] << " \n"[i == b.back()]; + for(auto i : c) + cout << a[i] << " \n"[i == c.back()]; + + return; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + + + +## B Olya and Game with Arrays + +最小的 + 选 n-1 组中的次小值 + +- 如果最小的不动,那么就是最小的加上其他所有组的次小值 +- 如果最小的动,这组变成加次小值,最小的移动到的组变成加最小值 + +两种情况是等价的 + + + +比赛的时候我是暴力枚举把哪 n-1 行的最小值扔到 另外一行 在加上这一行(包括被扔过来的)的最小值 + + + +```cpp +// 赛时代码 +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n, m; + cin >> n; + + vector vm1(n + 1), vm2(n + 1); + vector> a(n + 1); + + for (int i = 1; i <= n; i++) + { + cin >> m; + int minv1 = INF, minv2 = INF; + + a[i].resize(m + 1); + for (int j = 1; j <= m; j++) + { + cin >> a[i][j]; + + if (a[i][j] < minv1) + { + minv2 = minv1; + minv1 = a[i][j]; + } + else if (a[i][j] < minv2) + { + minv2 = a[i][j]; + } + } + + vm1[i] = minv1; + vm2[i] = minv2; + } + + LL ans = 0; + for (int i = 1; i <= n; i++) + { + LL res = 0; + int minv = vm1[i]; + for (int j = 1; j <= n; j++) + if (i != j) + { + res = res + (LL)vm2[j]; + minv = min(minv, vm1[j]); + } + res = res + (LL)minv; + ans = max(ans, res); + } + + cout << ans << endl; + + // for (int i = 1; i <= n; i++) + // cerr << i << ' ' << vm1[i] << ' ' << vm2[i] << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +from jiangly + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + vector a; + + int min1 = 1E9; + int min2 = 1E9; + LL ans = 0; + + for (int i = 0; i < n; i++) + { + int m; + cin >> m; + + a.resize(m); + for (int j = 0; j < m; j++) + { + cin >> a[j]; + } + + nth_element(a.begin(), a.begin() + 1, a.end()); + min1 = min(min1, a[0]); + min2 = min(min2, a[1]); + ans += a[1]; + } + + ans -= min2; + ans += min1; + + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + return 0; +} +``` + + + +> **Trick** +> +> nth_element(a.begin(), a.begin() + x, a.end()) +> +> 作用是将第(x + 1)小的数放在a[x]上 +> +> 并且满足 +> +> a[0] ~ a[x - 1] <= a[x] <= a[x] ~ a[n - 1] +> +> 所以 +> +> nth_element(a.begin(), a.begin() + 1, a.end()) +> +> 将第二小的数放到了a[1] +> +> 进而a[0]只能为最小的数 + + + +## C Another Permutation Problem + +求n的全排列中,以下式子的最大值 + +$(\sum_{i=1}^{n}p_{i}*i)-(max_{j=1}^{n}p_{j}*j)$ + + + +**法一**:打表 + +发现最优解是将某个后缀翻转,形如{1, 2, k,...,n, n - 1,...,k + 1} + +枚举翻转长度即可 + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + LL ans = 0; + + for (int i = 0; i <= n; i++) + { + LL res = 0; + LL maxv = i * i; + for (int j = 1; j <= i; j++) + { + res += (LL)j * j; + } + + maxv = i * i; + for (int j = i + 1, k = n; j <= n; j++, k--) + { + res += (LL)j * k; + maxv = max(maxv, (LL)j * k); + } + res -= maxv; + ans = max(ans, res); + } + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + while (t--) + { + solve(); + } + + return 0; +} +``` + + + + + +**法二**:from jiangly + +暴力 and 并查集 + + + +枚举$(max_{j=1}^{n}p_{j}*j)$的值,进行限制。 + +之后从第n位开始填,尽可能填大的数。 + +并查集的用于维护的是,如果我现在这个位置上可以填的最大的数是x,但是x已经被填过了。 + +因为在x填的时候让p[x]=x-1,所以find(x)会从x向更小的数找x-1,x-2...直到第一个没有填的数 + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +struct DSU +{ + vector f, siz; + + DSU() {} + DSU(int n) + { + init(n); + } + + void init(int n) + { + f.resize(n); + iota(f.begin(), f.end(), 0); + siz.assign(n, 1); + } + + int find(int x) + { + while (x != f[x]) + { + x = f[x] = f[f[x]]; + } + return x; + } + + bool same(int x, int y) + { + return find(x) == find(y); + } + + bool merge(int x, int y) + { + x = find(x); + y = find(y); + if (x == y) + { + return false; + } + siz[x] += siz[y]; + f[y] = x; + return true; + } + + int size(int x) + { + return siz[find(x)]; + } +}; + +void solve() +{ + int n; + cin >> n; + + int ans = 0; + for (int l = n * n;; l--) + { + DSU dsu(n + 1); + int sum = 0; + bool ok = true; + for (int i = n; i >= 1; i--) + { + int x = dsu.find(min(n, l / i)); + if (x == 0) + { + // 表示已经开始无法满足了 + ok = false; + break; + } + sum += i * x; + dsu.merge(x - 1, x); // p[x] = x - 1 + } + + if (!ok) + { + break; + } + ans = max(ans, sum - l); + } + + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + + + + + +## D Andrey and Escape from Capygrad + +发现对于 l r a b + +l到b的数都会跳到b,b到r的数不会动 + +故a和r是两个没有用的数,将所有线段的[l, b],区间合并即可 + +之后二分找第一个大于x的r即可 + + + +from jiangly + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + vector> seg(n); + for (int i = 0; i < n; i++) + { + int l, r, a, b; + cin >> l >> r >> a >> b; + seg[i] = {l, b}; + } + + sort(seg.begin(), seg.end()); + + vector> a; + for (auto [l, r] : seg) + { + if (!a.empty() && l <= a.back()[1]) + { + a.back()[1] = max(a.back()[1], r); + } + else + { + a.push_back({l, r}); + } + } + + int q; + cin >> q; + + for (int i = 0; i < q; i++) + { + int x; + cin >> x; + + int j = lower_bound(a.begin(), a.end(), array{x + 1, 0}) - a.begin() - 1; + if (j >= 0) + { + x = max(x, a[j][1]); + } + cout << x << " \n"[i == q - 1]; + } + return; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +## E Maximum Monogonosity + +DP + +题目: + +给两个长度均为 n 的数组 a, b + +对选取 [l, r] 一段 + +长度为 $r-l+1$ + +价值为 $\lvert a_l - b_r \rvert + \lvert a_r - b_l \rvert$ + +选取总长度为 k 的段,每个段都互不相交,求最大总价值 + + + +法一: + +暴力dp + 剪枝 + +$dp[i][j]$ 表示的是前i个字符,还需要总长度为j的片段的最大价值 + +**第一个循环:**i + +枚举到第i个点 + +**第二个循环:**len + +枚举最后一段的长度,即枚举是从哪个点转移过来 + +最后一段即为 [i-len+1, i] + +**第三个循环: **z + +枚举除去这段前,仍需要的段的总长度 + + + +```cpp +for (int i = 1; i <= n; i++) +{ + for (int len = 1; len <= i; len++) + { + int st = i - len + 1; + for (int z = len; z <= k; z++) + { + dp[i][z - j] = max(dp[i][z - j], dp[st - 1][z] + + (LL)abs(a[st] - b[i]) + abs(a[i] - b[st]))); + } + } + + // 因为dp[i][j] 表示的是前i个字符,还需要总长度为j的片段 + // 而每次上面的循环计算出来的dp[i][j]都是i这个点在目前的最后一段里的 + // 所以需要把i这个点不在目前的最后一段里的也max以下 + // 这个值就是dp[i - 1][j] + for (int j = 0; j <= k; j++) + { + dp[i][j] = max(dp[i - 1][j], dp[i][j]); + } +} +``` + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n, m; + cin >> n >> m; + + vector a(n + 1), b(n + 1); + + for (int i = 1; i <= n; i++) + cin >> a[i]; + for (int i = 1; i <= n; i++) + cin >> b[i]; + + vector> dp(n + 1, vector(m + 1)); + + for (int i = 1; i <= n; i++) + { + for (int len = 1; len <= i; len++) + { + int st = i - len + 1; + for (int z = max(len, m - (st - 1)); z <= min(m, n - (st - 1)); z++) + { + dp[i][z - len] = max(dp[i][z - len], dp[st - 1][z] + (LL)abs(a[st] - b[i]) + abs(a[i] - b[st])); + } + } + + for (int j = 0; j <= m; j++) + { + dp[i][j] = max(dp[i - 1][j], dp[i][j]); + } + } + + LL ans = 0; + for(int i = 0; i <= n; i ++) + ans = max(ans, dp[i][0]); + + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +法二: + +标准解法 + +参考 + + + + + + + +首先拆开绝对值 + +将对于$\lvert a_l - b_r \rvert + \lvert a_r - b_l \rvert$的维护转化成 + +对于$/+a_l + b_l/+a_l - b_l/-a_l + b_l/-a_l - b_l/$这四个值的维护 + + + +同时维护两个数组dp mx + +mx数组更新的是选择第一个点,即每一段的左端点 + +dp数组更新的是选择第二个点,即每一段的右端点 + + + +$dp[i][j]$:表示前i个点,选的段的总长度为j + +$mx[u][id]$:u表示是拆分出来的四个式子中的哪一个,id表示i-j的值为多少 + +因为每次选一段 [l, r] 长度 len 后 + +i变成ii=i+len,j变成jj=j+len,会发现一件神奇的事情是i-j==ii-jj + +所以每次转移的时候i-j的值是固定的 + +可以按照i-j的大小进行分类转移 + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int N = 3010; +const LL INF = 1e18; + +LL mx[4][N]; +LL dp[N][N]; + +int s1[4] = {1, 1, -1, -1}; +int s2[4] = {1, -1, 1, -1}; + +void solve() +{ + int n, k; + cin >> n >> k; + + vector a(n + 2), b(n + 2); + for (int i = 1; i <= n; i++) + cin >> a[i]; + for (int i = 1; i <= n; i++) + cin >> b[i]; + + auto get = [&](int x, int id, int u) -> LL + { + return dp[x][x - id] + a[x + 1] * s1[u] + b[x + 1] * s2[u]; + }; + + dp[0][0] = 0; + for (int i = 1; i <= k; i++) + dp[0][i] = -INF; + for (int i = 0; i < 4; i++) + { + for (int j = 0; j <= n; j++) + { + mx[i][j] = -INF; + } + } + + for (int u = 0; u < 4; u++) + { + mx[u][0] = get(0, 0, u); + } + + for (int i = 1; i <= n; i++) + { + for (int j = 0; j <= k; j++) + { + dp[i][j] = dp[i - 1][j]; + } + for (int j = 0; j <= min(k, i); j++) + { + int id = i - j; + for (int u = 0; u < 4; u++) + { + dp[i][j] = max(dp[i][j], mx[u][id] - s1[u] * b[i] - s2[u] * a[i]); + } + for (int u = 0; u < 4; u++) + { + mx[u][id] = max(mx[u][id], get(i, id, u)); + } + } + } + cout << dp[n][k] << '\n'; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + diff --git a/docs/ACM/CF/div2_893.md b/docs/ACM/CF/div2_893.md new file mode 100644 index 0000000..33dea3a --- /dev/null +++ b/docs/ACM/CF/div2_893.md @@ -0,0 +1,14 @@ +--- +title: CFdiv2_893 +description: (ABCDEF) +categories: + - CF +highlight_shrink: false +abbrlink: 7fd84b65 +date: 2023-08-18 00:00:00 +mathjax: true +copyright_author: devilran +copyright_author_href: +copyright_url: +copyright_info: +--- diff --git a/docs/ACM/CF/div2_899.md b/docs/ACM/CF/div2_899.md new file mode 100644 index 0000000..e1cb642 --- /dev/null +++ b/docs/ACM/CF/div2_899.md @@ -0,0 +1,314 @@ +--- +title: CFdiv2_899 +description: (ABCDEF) +categories: + - CF +highlight_shrink: false +abbrlink: 9f0da27b +date: 2023-09-25 00:00:00 +mathjax: true +copyright_author: devilran +copyright_author_href: +copyright_url: +copyright_info: +--- + + + + + +赛时写了ABCD,但C题卡了太久,b题其实完全暴力就可以,但是想歪了,最后也没时间重新写了,过了ACD + + + +## A + + + +### 题目 + + + +You are given a sequence $a_{1}, a_{2}, \ldots, a_{n}$. A sequence $b_{1}, b_{2}, \ldots, b_{n}$ is called good, if it satisfies all of the following conditions: + +- $b_{i}$ is a positive integer for $i = 1, 2, \ldots, n$; +- $b_{i} \neq a_{i}$ for $i = 1, 2, \ldots, n$; +- $b_{1} \lt\; b_{2} \lt\; \ldots \lt\; b_{n}$. + +Find the minimum value of $b_{n}$ among all good sequences $b_{1}, b_{2}, \ldots, b_{n}$. + + + +给定a序列,求满足条件的最小$b_n$ + + + +### 思路 + + + +n很小,直接从t=1开始对应到b就行,如果 $b_i$==$a_i$ , t ++; + + + +### code + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + vector a(n + 1); + for (int i = 1; i <= n; i++) + { + cin >> a[i]; + } + + LL ans = 0, now = 1; + for (int i = 1; i <= n; i++) + { + if (now == a[i]) + now++; + ans += now; + now++; + } + + now--; + cout << now << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t = 1; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +## B + +这道题n很小,其实直接暴力就可以,根本不需要思考方 + +### 题目 + +给定n个集合$S_i$, 记所有集合的并集为$S_{all}$, 求从中选取一些集合,这些集合的并集的元素数量需要严格小于$S_{all}$,求选取出来的集合的并集的元素数量的最大值 + + + +### 思路 + +挨个枚举全集中的每个元素,当这个元素不存在的时候,我可以把哪些集合进行合并。之后合并完最大值就行 + + + +### code + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; +const int N = 55; + +set mp[N], all; + +void solve() +{ + int n; + cin >> n; + + all.clear(); + for (int i = 1; i <= n; i++) + { + mp[i].clear(); + int m; + cin >> m; + + for (int j = 1; j <= m; j++) + { + int t; + cin >> t; + mp[i].insert(t); + all.insert(t); + } + } + + int ans = 0; + for (auto t : all) + { + set res; + for (int i = 1; i <= n; i++) + { + if (mp[i].find(t) != mp[i].end()) + { + continue; + } + + for (auto tt : mp[i]) + { + res.insert(tt); + } + } + + ans = max(ans, (int)res.size()); + } + + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +## C + + + +### 题目 + +有n张牌堆成一堆,每张牌上写了一个价值,有以下两个操作,求操作完可以获得的最大价值。任意时候都可以停止操作。(价值中存在负数,否则就全取完就好了) + +操作 --- 从上向下数第几张 + +- 拿走第奇数张,之后获得这张牌上的价值 +- 拿走第偶数张,之后直接将这张牌扔掉,并不获得这张牌的价值 + +注意,每次拿走一站牌后,所有牌的顺序会重新计算,奇偶性可能发生改变 + + + +### 思路 + + + +如果一定选取第i个元素 + +对于i后面的奇数位置的元素,可以倒着直接取完 + +对于i后面偶数位置的元素,可以取完i,之后后这些要取的元素,就变成奇数了 + +后缀和优化 + + + +所以枚举第一个要选取的元素即可 + +### code + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + vector a(n + 1), suf(n + 2); + for (int i = 1; i <= n; i++) + { + cin >> a[i]; + } + + suf[n + 1] = 0; + for (int i = n; i >= 1; i--) + { + suf[i] = suf[i + 1] + max(a[i], 0ll); + } + + LL ans = 0; + for (int i = 1; i <= n; i++) + { + ans = max(ans, (i % 2 == 1) * a[i] + suf[i + 1]); + } + + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + + + diff --git a/docs/ACM/CF/edu_155.md b/docs/ACM/CF/edu_155.md new file mode 100644 index 0000000..3d4870c --- /dev/null +++ b/docs/ACM/CF/edu_155.md @@ -0,0 +1,312 @@ +--- +title: CFedu_155 +description: (ABCDEF) +categories: + - CF +highlight_shrink: false +abbrlink: d7783771 +date: 2023-09-24 00:00:00 +mathjax: true +copyright_author: devilran +copyright_author_href: +copyright_url: +copyright_info: +--- + +{% note info flat %}Code Reference:jiangly {% endnote %} + +{% note success flat %}赛时过了ABC。 D题是经典题,循环里没有清零导致赛后才a{% endnote %} + + +## A. Rigged! + +举重 每个人有一个可以举起来的重量值s和次数e + +问使得第一个人赢,比赛的重量设置为多少?不行输出 -1 +s +**思路:** + +最优:按照第一个人的重量即可,看能否成立 + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + vector s(n), e(n); + bool ok = true; + for (int i = 0; i < n; i++) + { + cin >> s[i] >> e[i]; + if (i > 0 && s[i] >= s[0] && e[i] >= e[0]) + { + ok = false; + } + } + + cout << (ok ? s[0] : -1) << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` +## B. Chips on the Board + +现在有一个 n * n 的方格, 我需要从中选取一些方格,使得对于每一个方格,它所在的行或者列都至少有一个方格被选了 + +每一行或者每一列都有一个代价,选一个方格将加上这一行的代价和这一列的代价值 + +求最小代价 + +**思路:** + +要不然每行选一个,要不然每列选一个 + +每行选一个的时候,都位于最小代价的列即可;每列同理 + +选两个中更小的 + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + int n; + cin >> n; + + LL sa = 0; + int mina = 1E9; + for (int i = 0; i < n; i++) + { + int a; + cin >> a; + sa += a; + mina = min(mina, a); + } + + LL sb = 0; + int minb = 1E9; + for (int i = 0; i < n; i++) + { + int b; + cin >> b; + sb += b; + minb = min(minb, b); + } + + LL ans = min(sa + 1LL * n * minb, sb + 1LL * n * mina); + cout << ans << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + +## C. Make it Alternating + +有一个01串,需要经过多次删除操作,使得最后相邻的都不一样 + +求操作次数,以及操作方案数(每次删除两个不同位置的数算做不同方案) + +**思路:** + +操作次数:每个(连续段长度 - 1) + +操作方案:要删的数,直接是阶乘,因为顺序随便。保留的数,是每段的长度,选出来一个。这些乘起来就好 + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; +const LL mod = 998244353; + +void solve() +{ + string s; + cin >> s; + + int n = s.size(); + + LL ways = 1; + + int ans = 0; + for (int l = 0, r = 0; l < n; l = r) + { + while (r < n && s[l] == s[r]) + { + r++; + } + // len = (r - 1) - l + 1 = r - l + ans += r - l - 1; // len - 1 + ways = ways * (r - l) % mod; + } + + for (int i = 1; i <= ans; i++) + { + ways = ways * i % mod; + } + + cout << ans << " " << ways << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + +## D. Sum of XOR Functions + +给你一个长度为 $n$ 的数组 $a$ ,由非负整数组成。 + +您必须计算 $\sum_{l=1}^{n} \sum_{r=l}^{n} f(l, r) \cdot (r - l + 1)$ 的值,其中 $f(l, r)$ 是 $a_l \oplus a_{l+1} \oplus \dots \oplus a_{r-1} \oplus a_r$(字符 $\oplus$ 表示位向 XOR)。 + +由于答案可能非常大,因此请打印它的模数 $998244353$。 + +**思路:** + +经典题 + +`拆位` + +之后存下来 + +!x(即与 x 相反)的前缀异或和的个数 + +!x 的前缀异或和的下标之和 + +因为只有是 !x 这样 这一段 的异或是 x ^ !x = 1 才有贡献 + +同时注意 因为是前缀异或和 所以 s[a] ^ s[b] 的时候 + +计算的是 a+1~b 这一段 长度是 b-a + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; +const LL mod = 998244353; + +LL s1[30][2], s2[30][2]; +// s1[j][!x] 存储了到目前为止,第 j 位为 !x(即与 x 相反)的前缀异或和的个数 +// s2[j][!x] 存储了到目前为止,第 j 位为 !x 的前缀异或和的下标之和 + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int n; + cin >> n; + + vector s(n + 1); + for (int i = 0; i < n; i++) + { + int a; + cin >> a; + s[i + 1] = s[i] ^ a; + } + + LL ans = 0; + for (int i = 0; i <= n; i++) + for (int j = 0; j < 30; j++) + { + int x = (s[i] >> j) & 1; + ans = (ans + (i * s1[j][!x] - s2[j][!x]) % mod * (1 << j) % mod) % mod; + s1[j][x] = (s1[j][x] + 1) % mod; + s2[j][x] = (s2[j][x] + i) % mod; + } + + cout << ans << endl; + + return 0; +} +``` \ No newline at end of file diff --git a/docs/ACM/ICPC/ccpc2022mianyang.md b/docs/ACM/ICPC/ccpc2022mianyang.md new file mode 100644 index 0000000..ce31e1b --- /dev/null +++ b/docs/ACM/ICPC/ccpc2022mianyang.md @@ -0,0 +1 @@ + diff --git "a/docs/ACM/ICPC/icpc\347\275\221\347\273\234\350\265\233\347\254\254\344\272\214\345\234\272.md" "b/docs/ACM/ICPC/icpc\347\275\221\347\273\234\350\265\233\347\254\254\344\272\214\345\234\272.md" new file mode 100644 index 0000000..fe39c5b --- /dev/null +++ "b/docs/ACM/ICPC/icpc\347\275\221\347\273\234\350\265\233\347\254\254\344\272\214\345\234\272.md" @@ -0,0 +1,36 @@ +--- +title: ICPC网络赛第二场 +description: ICPC网络赛第二场 +categories: + - ICPC +highlight_shrink: false +mathjax: true +copyright_author: devilran +abbrlink: 786975e4 +date: 2023-10-01 00:00:00 +copyright_author_href: +copyright_url: +copyright_info: +--- + +{% note info flat %} +Code Reference: + +https://zhuanlan.zhihu.com/p/658033297 + +https://blog.csdn.net/qq_62817228/article/details/133214071 +{% endnote %} + +{% note success flat %} !!!{% endnote %} + + +## K Super-Knight + +n * n的棋盘,上下连接,左右连接。 + +棋子最开始在左下角,每移动一次会向上移动a,向右移动b + +问除了出发点外所有可以到达的点中,距离出发点的欧几里得距离的平方的最小值为多少 + +**思路:** + diff --git "a/docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/CF\346\225\260\345\255\246.md" "b/docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/CF\346\225\260\345\255\246.md" new file mode 100644 index 0000000..f6b87e9 --- /dev/null +++ "b/docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/CF\346\225\260\345\255\246.md" @@ -0,0 +1,305 @@ +--- +title: CF数学 +description: codeforces 数学 1500-1800 +categories: + - ACM-Math +highlight_shrink: false +mathjax: true +copyright_author: devilran +sticky: 2 +toc: true +toc_number: true +abbrlink: aa579273 +date: 2023-09-28 00:00:00 +copyright_author_href: +copyright_url: +copyright_info: +--- + +# RWADME + + + +## 1542B + +### 题目 + +- 1 在集合中 +- 给定 a 和 b ,如果 x 在集合中,那么 x*a 和 x+b 也在集合里 + +多组测试 问给定 n, a, b, n是否在集合中 + +### 思路 + +观察模数,加 b 不能改变 mod b 的值, 所以 n mod b 出现的模数智能通过 乘a来进行调整. + +a(a + (ab + b)) = a^2 + (a^2 + a) * b发现只会只有a^k这一项 mod b != 0 + + + +代码 => 找到 (a^k mod b == n mod b && a^k <= n) 最小的k, 如果没有则不存在 + +注意特判 + +- a == 1时, a^k <= n 永远不会跳出循环 + +- b == 1时, 任意数都成立 + + + +### code + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +void solve() +{ + LL n, a, b; + cin >> n >> a >> b; + + LL x = 1; + bool ok = false; + if (b == 1) + { + ok = true; + } + else if (a == 1) + { + if (n % b == 1) + ok = true; + } + else + { + while (x <= n) + { + if (x % b == n % b) + { + ok = true; + break; + } + x = x * a; + } + } + + if (ok) + cout << "Yes" << endl; + else + cout << "No" << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + + return 0; +} +``` + + + +## 1538F + +### 题目 + +给你两个整数 $l$和 $r$,其中 $l \lt r$。我们将在$l$的基础上加上$1$,直到结果等于$r$。因此,正好会进行 $r-l$ 次加法运算。对于每一个这样的加法,让我们来看看在它之后将被改变的位数。 + +例如 + +- 如果$l=909$,那么加 1 将导致$910$和$2$位数发生变化; +- 如果在$l=9$后面加 1,结果将是$10$,并且$2$位数字也将改变; +- 如果在$l=489999$后面加 1,结果将是$490000$,$5$位数也将改变。 + +更改后的位数总是构成以十进制书写的结果的后缀。 + +如果要从$l$得到$r$,每次加上$1$,则输出更改后的位数总数。 + + + +### 思路 + + + +将 l ~ r 转化为计算 fun(r) - fun(l) + +fun(x) 为计算 1 ~ x 的变换次数 + +对于 fun(x): 针对每一位进行考虑, 有多少个这个位置的变动就等于把这位变成个位之后有多少个数 + + + +### code + + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +int fun(int x) +{ + LL res = 0; + while (x) + { + res += x; + x /= 10; + } + return res; +} + +void solve() +{ + int l, r; + cin >> l >> r; + + cout << fun(r) - fun(l) << endl; +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int t; + cin >> t; + + while (t--) + { + solve(); + } + return 0; +} +``` + + + +## 1487D + + + +## 235A + + + +## 1349A + + +## 1458A + +You are given two positive integer sequences $a_1, \ldots, a_n$ and $b_1, \ldots, b_m$. For each $j = 1, \ldots, m$ find the greatest common divisor of $a_1 + b_j, \ldots, a_n + b_j$. + +**思路:** + +根据 gcd(a, b) = gcd(a, b - a) 来进行化简 + +gcd(a1 + bj, a2 + bj, ..., an + bj) + += gcd(a1 + bj, a2 - a1, a3 - a1, ... an - a1) + += gcd(a1 + bj, w) + +预处理出w即可 + + +```cpp +#include + +#define LL long long +#define ULL unsigned long long +#define x first +#define y second +#define endl "\n" + +using namespace std; + +typedef pair PII; +typedef pair PLL; + +const int INF = 0x3f3f3f3f; + +LL gcd(LL a, LL b) +{ + return !b ? a : gcd(b, a % b); +} + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(0), cout.tie(0); + + int n, m; + cin >> n >> m; + + vector a(n + 1), b(m + 1); + for (int i = 1; i <= n; i++) + { + cin >> a[i]; + } + + for (int i = 1; i <= m; i++) + { + cin >> b[i]; + } + + if (n == 1) + { + for (int i = 1; i <= m; i++) + { + cout << a[1] + b[i] << ' '; + } + cout << endl; + return 0; + } + + LL w = a[2] - a[1]; + for (int i = 3; i <= n; i++) + { + w = gcd(w, a[i] - a[1]); + } + + for (int i = 1; i <= m; i++) + { + cout << abs(gcd(a[1] + b[i], w)) << ' '; + } + cout << endl; + + return 0; +} +``` + + diff --git "a/docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/LG\346\225\260\345\255\246.md" "b/docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/LG\346\225\260\345\255\246.md" new file mode 100644 index 0000000..e5acc2b --- /dev/null +++ "b/docs/ACM/\344\270\223\351\242\230\350\256\255\347\273\203/Math/LG\346\225\260\345\255\246.md" @@ -0,0 +1,17 @@ +--- +title: Luogu数学 +description: Luogu数学 +categories: + - ACM-Math +highlight_shrink: false +mathjax: true +copyright_author: devilran +sticky: 2 +toc: true +toc_number: true +abbrlink: fada414 +date: 2023-09-28 00:00:00 +copyright_author_href: +copyright_url: +copyright_info: +--- diff --git a/docs/about/devilran.md b/docs/about/devilran.md index ad7b932..0a6e773 100644 --- a/docs/about/devilran.md +++ b/docs/about/devilran.md @@ -1 +1,9 @@ ## devilran.md + +有意思的网站 + +https://wdxtub.com/ + +https://blog.tonycrane.cc/ + +https://note.tonycrane.cc/ \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index e3e961e..bb413c5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,3 @@ -## index.md - -这里是devilran的note +!!! abstract + + hello! 这里是Devilranのnote \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 20f0272..c5f6a04 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -36,8 +36,6 @@ markdown_extensions: - attr_list - md_in_html - - extra: generator: false #删除页脚显示“使用 MkDocs 材料制造” social: @@ -57,6 +55,18 @@ nav: - ACM: - Knowledge: - DP: ACM/Knowledge/DP/换根dp.md + - CF: + - div2_892: ACM/CF/div2_892.md + - div2_893: ACM/CF/div2_893.md + - div2_899: ACM/CF/div2_899.md + - edu_155: ACM/CF/edu_155.md + - 模拟vp: + - CCPC 2022 mianyang: ACM/模拟vp/ccpc2022mianyang.md + - ICPC 2023 网络赛第二场: ACM/模拟vp/icpc网络赛第二场.md + - 专题训练: + - Math: + - CF数学: ACM/专题训练/Math/CF数学.md + - LG数学: ACM/专题训练/Math/LG数学.md - ML: - Pytorch的基本用法: ML/Pytorch.md - 基本模型: @@ -67,7 +77,7 @@ nav: - Linux: - Linux: Linux/Linux.md - OS: - - OS: os.md + - OS: OS/os.md - CTF: - CTF: CTF/CTF.md - 关于: