P9453 [ZSHOI-R1] 有效打击 题解
Link_Cut_Y · · 题解
抢个题解。
题意应该都知道了,就不放了。
首先分析一下部分分,排序按照本人思考的顺序。
以下将数字称为颜色,将数字段称为颜色段。默认颜色段连续且最长。
Substack 2
最简单的部分分。由于
Substack 3
在 sub2 上稍微加了点难度。
Substack 1
考虑将
然后考虑匹配的情况是怎样的。首先考虑放缩倍数为
实现时需要注意一些细节:对于选取子串
所以需要从
暴力匹配的复杂度
Substack 4
显然,匹配过程可以利用哈希实现。对于
由于我们实现时对于放缩比例需要化为最简,所以需要求最大公约数。因此时间复杂度
下面是对于 substack 2, 3, 4 的代码实现:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
using ULL = unsigned int;
const int N = 5000010;
const ULL P = 1000000007;
int n, m;
int a[N], b[N];
vector<pair<int, int> > A, B;
ULL h1[N], h2[N], h3[N], h4[N], p1[N], p2[N];
long long ans;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
scanf("%d", &a[i]);
for (int i = 1; i <= m; i ++ )
scanf("%d", &b[i]);
for (int i = 1; i <= m; ) {
int j = i;
for (; j <= m and b[j] == b[i]; j ++ );
B.push_back({b[i], j - i}); i = j;
}
for (int i = 1; i <= n; ) {
int j = i;
for (; j <= n and a[j] == a[i]; j ++ );
A.push_back({a[i], j - i}); i = j;
}
if (B.size() == 1) {
for (auto i : A) {
if (i.first == B.front().first)
ans += 1ll * i.second * (i.second + 1) >> 1;
}
cout << ans << endl;
return 0;
}
if (B.size() == 2) {
int p = B.front().first;
int q = B.back().first;
int x = B.front().second;
int y = B.back().second;
int d = __gcd(x, y);
x /= d, y /= d;
for (int i = 0; i < A.size() - 1; i ++ ) {
if (A[i].first == p and A[i + 1].first == q) {
if (1ll * A[i].second * y > 1ll * A[i + 1].second * x)
ans += A[i + 1].second / y;
else ans += A[i].second / x;
}
}
cout << ans << endl; return 0;
}
else {
p1[0] = p2[0] = 1;
for (int i = 1; i <= A.size(); i ++ ) {
h1[i] = h1[i - 1] * P + A[i - 1].first;
h2[i] = h2[i - 1] * P + A[i - 1].second;
p1[i] = p1[i - 1] * P;
}
for (int i = 1; i <= B.size(); i ++ ) {
h3[i] = h3[i - 1] * P + B[i - 1].first;
h4[i] = h4[i - 1] * P + B[i - 1].second;
p2[i] = p2[i - 1] * P;
}
auto get = [](int l, int r, ULL p[], ULL h[]) -> ULL {
return ULL(h[r] - h[l - 1] * p[r - l + 1]);
};
for (int l = 1; l <= A.size(); l ++ ) {
int r = l + B.size() - 1;
if (r > A.size()) break;
ULL H1 = get(l, r, p1, h1);
ULL H2 = get(1, B.size(), p2, h3);
if (H1 != H2) continue;
ULL H3 = get(l + 1, r - 1, p1, h2);
ULL H4 = get(2, B.size() - 1, p2, h4);
ULL p = A[l].second, q = B[1].second;
ULL d = __gcd(p, q); p /= d, q /= d;
if (ULL(H3 * q) != ULL(H4 * p)) continue;
if (1ll * A[l - 1].second * q < 1ll * B.front().second * p) continue;
if (1ll * A[r - 1].second * q < 1ll * B.back().second * p) continue;
ans ++ ;
}
cout << ans << endl;
return 0;
}
return 0;
}
/*
17 3
1 1 2 2 3 3 3 1 1 2 2 3 1 2 1 2 3
1 2 3
*/
关于此题的严格线性做法
很显然,复杂度瓶颈卡在求解最大公约数上。对于 需要线性 。由于赛时没有看到额外奖励,所以没拿到/kk/kk。
严格线性的代码没写,有写的神巨可以私我一下,我白嫖挂上。