题解:P14567 【MX-S12-T2】区间
chenxi2009 · · 题解
思路
简短的线性确定性做法。
首先我们尝试找出一些合法区间。尝试固定右端点
然后是喜闻乐见的性质发掘环节。
Observation 1
如果有两个合法区间相交(不算包含的情况),它们都是较劣的。
证明:这两个合法区间的交是一个合法区间。因为交在靠左的合法区间里,所以它里面的颜色在它的右边没有出现;同理在它的左边也没有出现,所以两个合法区间的交是合法区间,比这两个合法区间都要优。
Observation 2
如果有两个合法区间相互包含,较大的一个劣于较小的一个。
证明:注意到
综上,我们考虑给先前的做法加上剪枝:记录已求出的最靠右的合法区间的右端点
考虑记录每个右端点最终停下时的左右端点
然后结束了,因为每个位置最多被 check 成功
那个单调不减的性质用到了哪里?注意到这样子做避免了两种 Observation 所述的情况,即查出来的所有区间都是互不包含互不相交的,所以它们的长度之和
代码
#include<bits/stdc++.h>
#define fr(a,b,c) for(int a = (b);a <= (c);a ++)
using namespace std;
const int N = 2000000;
int n,c[N],v[N],f[N],mx[N],mn[N],mxr,L[N],R[N],it[N],l,r,now;
long long ans = 1e18,sum;
int main(){
cin.tie(0)->sync_with_stdio(0);
cin >> n;
fr(i,1,n) cin >> c[i],mn[i] = 1e9;
fr(i,1,n) cin >> v[i];
fr(i,1,n) cin >> f[i];
fr(i,1,n) mx[c[i]] = i,mn[c[i]] = min(mn[c[i]],i);//每种颜色出现最早和最晚的位置
fr(i,1,n){//枚举右端点
l = mn[c[i]],r = mx[c[i]],now = i - 1;//l,r 记录当前区间,now 表示下一个要检查的颜色位置
while(r == i && now >= l){
if(R[now] > i || L[now] <= mxr) break;//左端点和已有合法区间相交则不合法
r = max(r,R[now]),l = min(l,L[now]),now = it[now];
}
if(r == i && now < l){//[l,r] 全部检查完毕,扫出了一个合法区间
mxr = i,sum = 0;
fr(j,l,r) sum += f[j - l + 1] * v[j];
ans = min(ans,sum);//统计答案
}
else L[i] = l,R[i] = r,it[i] = now;
}
printf("%lld\n",ans);
return 0;
}
笑点解析:貌似第一步还是第二步的做法就能通过原数据了。谴责脚造数据。