杂题 Part III
P14002
树的做法充分容易,考虑基环树,发现当前准备回溯是,由于在环上所以有 \(2\) 个被标为“在递归栈内”的结点。
我们任意访问一个,发现若周围有 \(2\) 个“在递归栈内”的结点,这个点一定不是父亲,不用动它,因为每次结点给出顺序相同,我们第一次找有第一个 \(2\),第二次找最后一个 \(2\)。否则发现我们不妨给这个点标记为 \(0\) 以区分。而我们来的时候给原来结点打一个新的标记,就可以知到我们现在在处于什么状态。
最后可能会有两个 \(2\) 均只有一个“在递归栈内”的结点与之相邻,画个图可以发现两个点必有一根,走哪边都是等价的。
AT_hitachi2020_f
考虑发掘性质:
- 图的直径端点只有 \(2\) 个,否则可以把另一个直径端点操作成距离比原来小 \(1\) 的点,不影响直径长度。
- 考虑刻画不能加边的性质,发现我们钦定一个点到直径中心(可能是一条边,这时不妨视为一个点,到两个端点的距离为 \(0.5\))的距离,发现距离相差不超过 \(1\) 的点之间可以连边,其余不能连边,于是问题转化为钦定距离大小。
- 只有原树上的边会对距离差产生限制,容易树形 dp,状态记录当前子树中能作为直径端点的点有多少个,复杂度线性。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline ll Read() {
int sig = 1; ll num = 0; char c = getchar();
while(!isdigit(c)) { if(c == '-') sig = -1; c = getchar(); }
while(isdigit(c)) num = (num << 3) + (num << 1) + (c ^ 48), c = getchar();
return num * sig;
}
void Write(ll x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) Write(x / 10);
putchar((x % 10) ^ 48);
}
const int N = 200005;
const ll Mod = 998244353, inv2 = (Mod + 1) / 2;
int n, dep[N], maxdep[N];
ll f[N][3][3], g[3][3];
vector<int> e[N];
void Dfs(int u, int fa) {
maxdep[u] = dep[u] = dep[fa] + 1;
for(auto v : e[u]) if(v != fa) Dfs(v, u), maxdep[u] = max(maxdep[u], maxdep[v]);
}
void Add(ll &x, ll y) { x += y; if(x >= Mod) x -= Mod; }
void Dfs2(int u, int fa, int dep) {
if(!dep) f[u][1][1] = 1;
else f[u][0][0] = 1;
for(auto v : e[u]) if(v != fa) {
int i, j, k, l, w; Dfs2(v, u, dep - 1), memset(g, 0, sizeof(g));
for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) for(k = 0; k < 3; k++) for(l = 0; l < 3; l++) {
for(w = -1; w <= 1; w++) Add(g[w == 1 ? min(i + k, 2) : i][w == -1 ? min(j + l, 2) : j], f[u][i][j] * f[v][k][l] % Mod);
}
memcpy(f[u], g, sizeof(f[u]));
}
}
int main() {
int i, x, y, z; n = Read();
for(i = 1; i < n; i++) { int u = Read(), v = Read(); e[u].emplace_back(v), e[v].emplace_back(u); }
Dfs(1, 0); for(i = 1; i <= n; i++) if(dep[x] < dep[i]) x = i;
Dfs(x, 0); for(i = 1; i <= n; i++) if(dep[x] < dep[i]) x = i;
if(dep[x] & 1) {
for(i = 1; i <= n; i++) if(dep[i] == (dep[x] + 1) / 2 && maxdep[i] == dep[x]) y = i;
Dfs2(y, 0, dep[x] / 2), Write(f[y][1][1] * inv2 % Mod);
}
else {
for(i = 1; i <= n; i++) {
if(dep[i] == dep[x] / 2 && maxdep[i] == dep[x]) y = i;
if(dep[i] == dep[x] / 2 + 1 && maxdep[i] == dep[x]) z = i;
}
Dfs2(y, z, dep[x] / 2 - 1), Dfs2(z, y, dep[x] / 2 - 1);
Write((f[y][1][0] + f[y][1][1] + f[y][1][2]) * (f[z][1][0] + f[z][1][1] + f[z][1][2]) % Mod);
}
}
CF1450H2
考虑刻画 \(f\),发现:
- 最优情况下一定是贪心匹配相邻同色点。
证明:考虑调整。
如图,D 区颜色全部相同,假设有形如黑边的白点的匹配,那么 \(A, B\) 之间的黑点匹配会有 \(2\) 的贡献,\(A/B, C\) 之间的黑点匹配会有 \(1\) 的贡献,然后调整为红边后,那么 \(A, B\) 之间的黑点匹配会有 \(0\) 的贡献,剩下的贡献不变,显然更优。
为了方便,我们令:\(a_{0/1}\) 表示偶数/奇数位置上的黑点个数,\(b_{0/1}\) 表示偶数/奇数位置上的白点个数,\(c_{0/1}\) 表示偶数/奇数位置上的问号个数,\(B = c_0 + c_1\)。
单个问题答案是 \(\frac{|a_0 - a_1|}{2}\),有原问题答案:
即:
令 \(c_1 + i - j = x\),又有:
再令 \(A = -(a_0 - a_1 - c_1), B = c_0 + c_1\),有:
拆绝对值:
后面那个太丑了:
进一步拆一下:
利用 \(\binom{a}{b}b = \binom{a - 1}{b - 1}a\):
这里对于 \(y \in \{0, 1\}\) 一定有:
所以先把原式变一下:
这里 \(A, B\) 的变化量是 \(O(1)\) 的,于是有:
可以做到 \(O(n + q)\),注意特判 \(B\) 很小的情况。
P14858
考虑 \((a + bi)(b + ai) = (a^2 + b^2)i\),于是我们特殊处理 \(ab \bmod p = 0\) 和 \(a = b\) 的情况,剩下只需处理(令 \(t = \lfloor \frac{n}{p} \rfloor\),\(r = n \bmod p\)):
拆开乘方后均可以化成如下形式:
令 \(k = i^2 + j^2\):
可以使用 NTT,需要处理一下小于号的限制。


浙公网安备 33010602011771号