Luogu3587[POI2015]POD - hash + 单调队列
Solution
还是去看了题解。 感谢大佬的博客→ 题解传送门
是一道思路比较新的题。
搞一个前缀和, 记录前 $i$ 个位置每种颜色的出现次数, 如果位置 $i$ 是 颜色 $a[i]$ 的最后一个位置, 就把颜色 $a[i]$ 清零。
这样就可以保证两个可以分割的点, 它们的前缀和一定是相同的。
$k$ 种颜色的前缀和不好维护(太大了), 就开到hash里面去, 用hash检验是否相等。
两个分割点 $r, l$ 要尽可能满足 $r-l$ 接近 $n \div 2$, 用单调队列维护
Code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define rd read() 5 #define ll long long 6 #define R register 7 using namespace std; 8 9 const int N = 1000005, base1 = 999979, base2 = 999983, mod1 = 1e9 + 7, mod2 = 1e9 + 9; 10 11 ll po1[N], po2[N], sum1, sum2; 12 int last[N], cnt[N], n, k, a[N]; 13 14 struct node { 15 int id; 16 ll s1, s2; 17 }b[N]; 18 19 inline int read() { 20 int X = 0, p = 1; char c = getchar(); 21 for (; c > '9' || c < '0'; c = getchar()) 22 if (c == '-') p = -1; 23 for (; c >= '0' && c <= '9'; c = getchar()) 24 X = X * 10 + c - '0'; 25 return X * p; 26 } 27 28 int cmp(const node &A, const node &B) { 29 if (A.s1 != B.s1) return A.s1 < B.s1; 30 if (A.s2 != B.s2) return A.s2 < B.s2; 31 return A.id < B.id; 32 } 33 34 int jud(int x, int y) { 35 if (b[x].s1 != b[y].s1) return 0; 36 if (b[x].s2 != b[y].s2) return 0; 37 return 1; 38 } 39 40 void cmin(int &A, int B) { 41 if (A > B) A = B; 42 } 43 44 int Abs(int A) { 45 return A > 0 ? A : -A; 46 } 47 48 int main() 49 { 50 n = rd; k = rd; 51 for (R int i = 1; i <= n; ++i) 52 a[i] = rd; 53 po1[0] = po2[0] = 1; 54 for (R int i = 1; i <= k; ++i) 55 po1[i] = po1[i - 1] * base1 % mod1, 56 po2[i] = po2[i - 1] * base2 % mod2; 57 for (R int i = 1; i <= n; ++i) 58 cnt[a[i]]++, last[a[i]] = i; 59 for (R int i = 1; i <= n; ++i) { 60 (sum1 += po1[a[i]]) %= mod1; 61 (sum2 += po2[a[i]]) %= mod2; 62 if (i == last[a[i]]) 63 sum1 = (sum1 - po1[a[i]] * cnt[a[i]] % mod1) % mod1, 64 sum1 = (sum1 + mod1) % mod1, 65 sum2 = (sum2 - po2[a[i]] * cnt[a[i]] % mod2) % mod2, 66 sum2 = (sum2 + mod2) % mod2; 67 b[i].id = i, 68 b[i].s1 = sum1, 69 b[i].s2 = sum2; 70 } 71 sort(b + 1, b + 1 + n, cmp); 72 ll ans1 = 0; int ans2 = n; 73 int mid = (n + 1) >> 1; 74 for (int i = 1, j = 1; i <= n; i = j) { 75 while (j <= n && jud(i, j)) j++; 76 ans1 += 1LL * (j - i) * (j - i - 1) / 2; 77 for (int l = i, r = i; r < j; ++r) { 78 while (l < r && b[r].id - b[l].id >= mid) l++; 79 cmin(ans2, Abs(n - 2 * (b[r].id - b[l].id))); 80 if (l != i) 81 cmin(ans2, Abs(n - 2 * (b[r].id - b[l - 1].id))); 82 } 83 } 84 printf("%lld %d\n", ans1, ans2); 85 }