题解:P14567 【MX-S12-T2】区间
话说我看到这个题的第一眼感觉是个消消乐,没想到是个小小乐。
本题解介绍三种方法和一种经典的哈希模型:
异或哈希
顾名思义就是基于异或的哈希,那么我们先思考异或有什么性质:
-
a_i \oplus a_i = 0 -
-
a_i \oplus a_j = a_j \oplus a_i
那么我们可以给每一个数字一个哈希值,然后进行配对。
下面我们举一个例子:
给定一个
上述例子存在线性的做法,但是在此介绍异或哈希:
首先对于每个数字赋一个随机权值,然后求出来前
下面开始介绍我们这一个题目:
首先是看到要求价值最小的一个区间使区间内的数字在区间外都不存在。
所以我们可以直接考虑预处理出来每个颜色的左端点和右端点。
考虑存在多个区间存在包含关系,下面我们考虑一个贪心:
对于多个相互包含的区间,选择最小的那个区间的价值一定是这些里面最优秀的。
这个证明很显然,肯定对于每一个
此时我们的有效区间两两相离,所以我们只要暴力的对每个区间扫一边即可。
方法1 异或哈希
就是对于每个
mt19937_64 rnd(time(0));
int n, v[N], f[N];
ll t[N],ans = LLONG_MAX;
vector<int> p[N];
unordered_map<ll, int> h;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1, x; i <= n; i++) cin >> x, p[x].push_back(i);
for (int i = 1; i <= n; i++) cin >> v[i];
for (int i = 1; i <= n; i++) cin >> f[i];
for (int i = 1; i <= n; i++)
if (p[i].size() > 1) {
for (auto it = next(p[i].begin()); it != p[i].end(); it++) {
ll now = rnd();
t[*p[i].begin()] -= now;
t[*it] += now;
}
}
h[0] = 0;
int mx = 0, cnt = 0;
for (int i = 1; i <= n; i++) {
t[i] += t[i - 1];
if (h.count(t[i])) {
int l = h[t[i]] + 1, r = i;
if (l > mx) {
mx = l;
ll sum = 0;
for (int j = l; j <= r; j++) sum += 1ll * v[j] * f[j - l + 1], cnt++;
ans = min(ans, sum);
}
}
h[t[i]] = i;
}
cout << ans;
}
方法2 双指针
我们很明显发现区间只有包含和相离两种情况,此时我们可以倒着扫