原题:
E. Permutation Separation
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a permutation p1,p2,…,pn (an array where each integer from 1 to n appears exactly once). The weight of the i-th element of this permutation is ai.
At first, you separate your permutation into two non-empty sets — prefix and suffix. More formally, the first set contains elements p1,p2,…,pk the second — pk+1,pk+2,…,pn, where 1≤k . After that, you may move elements between sets. The operation you are allowed to do is to choose some element of the first set and move it to the second set, or vice versa (move from the second set to the first). You have to pay ai dollars to move the element pi. Your goal is to make it so that each element of the first set is less than each element of the second set. Note that if one of the sets is empty, this condition is met. For example, if p=[3,1,2] and a=[7,1,4], then the optimal strategy is: separate p into two parts [3,1] and [2] and then move the 2-element into first set (it costs 4). And if p=[3,5,1,6,2,4], a=[9,1,9,9,1,9], then the optimal strategy is: separate p into two parts [3,5,1] and [6,2,4], and then move the 2-element into first set (it costs 1), and 5-element into second set (it also costs 1). Calculate the minimum number of dollars you have to spend. The first line contains one integer n The second line contains n integers p1,p2,…,pn (1≤pi≤n). It’s guaranteed that this sequence contains each element from 1 to n exactly once. The third line contains n integers a1,a2,…,an (1≤ai≤109). Print one integer — the minimum number of dollars you have to spend. Input 3 Output 4 Input 4 Output 3 Input 6 Output 2 中文: 代码: 解答: e题过了300多个人说明不难,呵呵 首先考虑个暴力解法,看看能发现什么数上的规律 每次枚举分割点i,再枚举左部分最大值k,计算当前的代码取最小。伪代码如下: 上面这种算法需要O(n^3)的时间复杂度,无法承受 首先要初始化每个叶子节点的值,初始时表示左侧区间是空的,所以每个叶子节点k的值表示将所有小于等于k的p[i]的和(有点绕口),按照上面的例子 初始化完成后,枚举分割点(初始时左侧为空,枚举分割点表示初始时左侧分别存在前i个数时对应的计算结果) 那么左部分最大值分别为1和2的节点需要把3移动到右侧,即将叶子节点1和叶子节点2都加上3对应的代价2,即将区间[0,2]加上v[1] 由于线段树维护的是整个区间的最小值,那么在遍历了所有分割点的情况后,得到的结果就是最优结果
Input
(2≤n≤2⋅10^5) — the length of permutation.
Output
Examples
3 1 2
7 1 4
2 4 1 3
5 9 8 3
3 5 1 6 2 4
9 1 9 9 1 9
给你一个序列p[i],让你分成左右两部分,要求左部分的最大的数比右部分最小的数小,每个数都右代价,可以将左部分或者右部分的数移动到另外一个部分,移动的代价为v[i],现在问你实现上面的要求最小的代价是多少。 #include
int ans = INT_MAX;
for (int i = 1;i<=n;i++) //枚举分割点
{
for (int k=1;k<=n;k++)// 枚举左部分区间最大值
{
int tmp =0;
for (int j = 1;j<=n;j++) // 计算区间的代价
{
// 左边出现数据大于k 或者右边出现数据小于等于k
if (p[j] > k && j < i || p[j] <= k && j >=i)
{
tmp += v[j];
}
}
}
ans = min(ans, tmp);
}
想想优化方法,由于输入的序列最大值不超过n,考虑使用线段树方法来优化
线段树覆盖区间[0,n],树上的每个叶子节点k表示当前左侧区间最大值为k时的最小代价。
同样,枚举分割点i,表示将p[i]加到左侧区间时的最小代价。
举个例子,现在数据如下:
6
3 5 1 6 2 4 —>p[i]
2 3 4 5 6 7 —>v[i]
叶子节点为1对应的代价是4;
叶子节点为2时,对应的代价为p[i]=1与p[i]=2的代价和即,4+6=10
叶子节点为3时,对应的代价为p[i]=1 p[i]=2 p[i]=3的代价和,即4+6+2=12
依次类推计算出,由上可见可以保存每个p[i]对应的下标,然后计算前缀和
假设当前枚举的分割点i=1
即初始时3在左部分,如下:3 | 5 1 6 2 4
还要处理左部分最大值为3,4,5,6的情况,由于初始时左侧部分已经存在3,且3,4,5,6的作为叶子节点的初始结果已经包含3的值,此时需要减去v[1]