对于这个 \(\operatorname{hash}(A_L, \cdots, A_R)\),一个比较经典的想法是做差分,即令 \(s_i = \sum\limits_{j = 1}^i A_j B^{i - j}\)。
于是 \(\operatorname{hash}(A_L, \cdots, A_R) = s_R - s_{L - 1}\times B^{R - L + 1}\not = 0\)。
那么也就是 \(s_R\not = s_{L - 1}\times B^{R - L + 1}\)。
此时这里只有右边带了个 \(B\),肯定是尽量想让两边形式尽量相近的,于是可以考虑同乘 \(B^{-R}\),就转化为了 \(s_R\times B^{-R} = s_{L - 1}\times B^{-(L - 1)}\)。
同时也能发现,对于 \(s_i\times B^{-i}\),不管取什么值都存在合法的 \(x_i\) 的选取。
这是因为如果知道了 \(s_{i - 1}\times B^{- (i - 1)}\),有式子 \(B s_{i - 1} + x_i = s_i\),那同除 \(B^i\),有 \(s_{i - 1}B^{-(i - 1)} + x_i\times B^{-i} = s_i\times B_{-i}\),因为 \(P\in \mathbb{P}, 1\le B < P\),所以一定有解。
那么就可以令 \(y_i = s_i\times B^{-i}\)。
如果存在 \(\operatorname{hash}(A_L, \cdots, A_R)\not = 0\),那就相当于是 \(y_R\not = y_{L - 1}\)。
那么就可以考虑转化图论,连边 \((L - 1, R)\)。
考虑现在什么情况是不合法的,能发现是如果存在 \(y_i\ge P\) 就会不合法。
那么如果选出许多点互相都没有连边,那么这些点的 \(y_i\) 就可以被赋成一个值。
于是可以考虑设 DP,\(f_s\) 表示已经确定了 \(s\) 集合内的数的取值,最少用的数的数量。
直接子集 DP,若最后 \(f_U\le P\)(\(U\) 表示全集) 就合法。
时间复杂度 \(\mathcal{O}(3^n)\)。
#include<bits/stdc++.h>
int f[1 << 17], g[1 << 17], ok[1 << 17];
int main() {
int P, n, m; scanf("%d%*d%d%d", &P, &n, &m);
n++;
g[0] = (1 << n) - 1;
for (int i = 0; i < n; i++)
g[1 << i] = (1 << n) - 1;
for (int l, r; m--; ) {
scanf("%d%d", &l, &r), l--;
g[1 << l] ^= 1 << r, g[1 << r] ^= 1 << l;
}
ok[0] = 1;
for (int s = 1; s < (1 << n); s++) {
int x = __builtin_ctz(s);
ok[s] = ok[s ^ (1 << x)] && (g[s ^ (1 << x)] >> x & 1);
g[s] = g[s ^ (1 << x)] & g[1 << x];
}
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for (int s = 1; s < (1 << n); s++)
for (int t = s; t; t = (t - 1) & s)
if (ok[t])
f[s] = std::min(f[s], f[s ^ t] + 1);
puts(f[(1 << n) - 1] <= P ? "Yes" : "No");
return 0;
}
标签:Atcoder,ARC171D,times,cdots,Rolling,hash,合法,operatorname,DP
From: https://www.cnblogs.com/rizynvu/p/18360161