今天的题目
T1
\(90pts\)。
赛时树状数组写挂了。
发现没有特判第一个数是 \(0\)。
我的思路是,\(cnt[x]\) 表示对于所有的 \(h[i] \geq x\) 可以构成多少个区间。
先离散化。
对于当前 \(h[i]\),若 \(h[i - 1] < h[i]\),则 \(h[i - 1] + 1\) 到 \(h[i]\) 的 \(cnt\) 会加一,因为 \(i\) 是新区间的开始。
若 \(h[i - 1] \geq h[i]\), 则不会有任何的贡献,因为如果 \(i\) 存在,那么 \(i - 1\) 也会存在,所以 \(i\) 不是新区间的开始。
这个直接在树状数组上差分。
还要特判 \(h[1] = 0\)。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#define lowbit(x) x & (-x)using std::cin;
using std::cout;
const int N = 1e6 + 10;int n;
int max_val;
int h[N];
int b[N];
int re[N];
int sum[N];
std::vector<int> v;void add(int x, int val)
{for (; x <= max_val; x += lowbit(x))sum[x] += val;
}
int query(int x)
{int ret = 0;for (; x; x -= lowbit(x))ret += sum[x];return ret;
}
void read(int &x)
{x = 0;int f = 1;char c = getchar();while (!isdigit(c)){if (c == '-')f = -f;c = getchar();}while (isdigit(c)){x = x * 10 + c - '0';c = getchar();}x *= f;
}int main()
{read(n);for (int i = 1; i <= n; ++i){read(h[i]);v.push_back(h[i]);}std::sort(v.begin(), v.end());v.erase(std::unique(v.begin(), v.end()), v.end());for (int i = 1; i <= n; ++i){b[i] = std::lower_bound(v.begin(), v.end(), h[i]) - v.begin() + 1;re[b[i]] = h[i];}for (int i = 1; i <= n; ++i)max_val = std::max(max_val, b[i]);if (h[1] > 0){add(1, 1);if (b[1] + 1 <= max_val)add(b[1] + 1, -1);}for (int i = 2; i <= n; ++i){if (b[i - 1] < b[i]){add(b[i - 1] + 1, 1);if (b[i] + 1 <= max_val)add(b[i] + 1, -1);}}int max = 0;for (int i = 1; i <= max_val; ++i){int now = query(i);if (now > max)max = now;}cout << max << '\n';return 0;
}
T2
写了第一个分段。
这道题其实一眼数位 \(DP\) 。
\(\mathcal{AK\_Dream}\):这是一道简单题。
但是我不会。
先考虑 \(L = R\) 的情况。
令 \(dp[i][j]\) 表示,考虑到 \(i\),所有的后缀中,\(\%k\) 余 \(j\) 的方案数。
\(dp[i + 1][(j * 10 + num[i]) \% k] += dp[i][j]\)。
\(dp[i + 1][num[i] \% k] += dp[i][j]\)。
同理,直接把这个转化一下就行了。
老师的代码:
#include <bits/stdc++.h>
#define N 50005
#define K 105
using namespace std;const int mod = 1000000007;
inline int qmod(int x) { return x < mod ? x : x - mod; }
inline void qadd(int &x, int y) { (x += y) >= mod ? (x -= mod) : 0; }char L[N], R[N];
int k, dp[2][N][K];
int tenc[N], upc[N];int DP(char *T, int d, int sum, bool up, bool zero)
{int ans = 0;if (d < 0){return sum == -2;}if (!zero && dp[up][d][sum + 2] != -1){return dp[up][d][sum + 2];}int mx = up ? T[d] - '0' : 9;for (int i = 0; i <= mx; i++){bool new_up = up && (i == mx), new_zero = zero && (i == 0);if (sum >= 0){int new_sum = (sum * 10 + i) % k;if (new_sum == 0){qadd(ans, DP(T, d - 1, -2, new_up, new_zero));}qadd(ans, DP(T, d - 1, new_sum, new_up, new_zero));}else if (sum == -1){if (!new_zero){qadd(ans, DP(T, d - 1, i % k, new_up, new_zero));if (i % k == 0){qadd(ans, DP(T, d - 1, -2, new_up, new_zero));}}qadd(ans, DP(T, d - 1, -1, new_up, new_zero));}else if (sum == -2){qadd(ans, DP(T, d - 1, -2, new_up, new_zero));}}if (!zero)dp[up][d][sum + 2] = ans;return ans;
}int calc(char *T, int len)
{memset(dp, -1, sizeof(dp));int ans = DP(T, len - 1, -1, true, true);return ans;
}void solve()
{scanf("%s %s %d", L, R, &k);int lenL = strlen(L), lenR = strlen(R);reverse(L, L + lenL);reverse(R, R + lenR);for (int i = 0; i < lenL; i++){if (L[i] != '0'){L[i]--;break;}L[i] = '9';}if (L[lenL - 1] == '0')--lenL;int ans = qmod(calc(R, lenR) - calc(L, lenL) + mod);printf("%d\n", ans);
}int main()
{int ttt;scanf("%d", &ttt);while (ttt--)solve();return 0;
}
T3
没有写 #include <vector>
。
本地编译过了。
\(25pts \to 0pt\)。
这道题,先 \(dfs\) 出 \(a\) 到 \(b\) 的那条路径,然后路径上的每个点下面都会挂着一个子树,我们求出 \(maxd[x]\) = \(x\) 点在子树中最远走的路径长度。
如果小 \(a\) 走着走着走到了一个子树里,那么小 \(a\) 的答案肯定就是 \(maxd[a]\),而小 \(b\) 可以选择 \(next\_point[a]\) 到 \(b\) 的任意一个子树中选择一个子树去走.
我们先看 \(a,b\) 都顶到头的时候,也就是他们只能走一个子树的时候。
这是,我们求出这时的答案 \(now1\)。
假设最后一步是 \(a\) 走的。
那么我们让 \(a\) 退回去,那么假设 \(a\) 要在这个地方进子树,就可以统计答案。
\(b\) 也同理。
但是我调了一个晚上没有调出来。。。
代码:
#include <bits/stdc++.h>
#define N 500005
using namespace std;template <typename T>
inline void read(T &num)
{T x = 0, f = 1;char ch = getchar();for (; ch > '9' || ch < '0'; ch = getchar())if (ch == '-')f = -1;for (; ch <= '9' && ch >= '0'; ch = getchar())x = (x << 3) + (x << 1) + (ch ^ '0');num = x * f;
}int n, A, B;
vector<pair<int, int>> E[N];
int chain[N], clen[N], cnt, maxd[N];
int lg2[N], st1[21][N], st2[21][N];bool dfs(int x, int dest, int fa)
{if (x == dest){chain[++cnt] = x;clen[cnt] = 0;return true;}for (auto [y, w] : E[x])if (y != fa){if (dfs(y, dest, x)){chain[++cnt] = x;clen[cnt] = w;return true;}}return false;
}int getd(int x, int fa)
{int mx = 0;for (auto [y, w] : E[x])if (y != fa){mx = max(mx, w + getd(y, x));}return mx;
}inline int qry1(int l, int r)
{int k = lg2[r - l + 1];return max(st1[k][l], st1[k][r - (1 << k) + 1]);
}inline int qry2(int l, int r)
{int k = lg2[r - l + 1];return max(st2[k][l], st2[k][r - (1 << k) + 1]);
}int main()
{read(n);read(A);read(B);for (int i = 1, u, v, w; i < n; i++){read(u);read(v);read(w);E[u].push_back({v, w});E[v].push_back({u, w});}dfs(B, A, 0);chain[0] = chain[cnt + 1] = 0;for (int i = 2; i <= cnt; i++)clen[i] += clen[i - 1];for (int i = 1; i <= cnt; i++){int x = chain[i];for (auto [y, w] : E[x]){if (y != chain[i - 1] && y != chain[i + 1])maxd[i] = max(maxd[i], w + getd(y, x));}st1[0][i] = maxd[i] + clen[i];st2[0][i] = maxd[i] - clen[i];}lg2[1] = 0;for (int i = 2; i <= cnt; i++)lg2[i] = lg2[i >> 1] + 1;for (int l = 1; (1 << l) <= cnt; l++){for (int i = 1; i + (1 << l) - 1 <= cnt; i++){st1[l][i] = max(st1[l - 1][i], st1[l - 1][i + (1 << (l - 1))]);st2[l][i] = max(st2[l - 1][i], st2[l - 1][i + (1 << (l - 1))]);}}int ans = 0;if (cnt & 1)ans = st2[0][((cnt + 1) >> 1) + 1] + clen[cnt] - st1[0][(cnt + 1) >> 1];elseans = st1[0][(cnt + 1) >> 1] - (st2[0][((cnt + 1) >> 1) + 1] + clen[cnt]);for (int i = cnt - 3; i >= 0; i--){int l = 1 + ((i + 1) >> 1), r = cnt - (i >> 1);if (i & 1)ans = max(st2[0][r] + clen[cnt] - qry1(l, r - 1), -ans);elseans = max(st1[0][l] - (qry2(l + 1, r) + clen[cnt]), -ans);}printf("%d\n", ans);return 0;
}
T4
猜了个 \(30pts\) 的结论,实则 \(10pts\)。
有点懵。贴一个老师的题解:
这是代码:
#include <bits/stdc++.h>
#define N 1000005
#define M 105
using namespace std;
typedef long long ll;
typedef __int128 i128;template <typename T>
void write(T num)
{if (num < 0)putchar('-'), num = -num;if (num >= 10)write(num / 10);putchar(num % 10 + '0');
}int pr[N], np[N], ptot;
void init()
{int n = 1000000;for (int i = 2; i <= n; i++){if (!np[i])pr[++ptot] = i;for (int j = 1; j <= ptot && i * pr[j] <= n; j++){np[i * pr[j]] = 1;if (i % pr[j] == 0)break;}}
}ll pfac[M];
int vis[M], match[M], rev[M];bool dfs(int x, int m)
{for (int j = 1; j <= m; j++)if (!vis[j] && x % pfac[j] != 0){vis[j] = 1;if (!match[j] || dfs(match[j], m)){match[j] = x;rev[x] = j;return true;}}return false;
}void solve()
{int n, m;ll k;scanf("%d %lld", &n, &k);if (n == 2){printf("%lld %lld\n", 2 * k, k);return;}ll tmp = k;m = 0;for (int i = 1; i <= ptot && 1ll * pr[i] * pr[i] <= tmp; i++){if (tmp % pr[i] == 0){pfac[++m] = pr[i];while (tmp % pr[i] == 0)tmp /= pr[i];}}if (tmp)pfac[++m] = tmp;if (m < n){puts("-1");return;}for (int i = 1; i <= n; i++)rev[i] = 0;for (int j = 1; j <= m; j++)match[j] = 0;for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++)vis[j] = 0;if (!dfs(i, m)){puts("-1");return;}}for (int i = 1; i <= n; i++){write((i128)i * k / pfac[rev[i]]);putchar(' ');}putchar('\n');
}int main()
{init();int ttt;scanf("%d", &ttt);while (ttt--)solve();return 0;
}