CF1295E Permutation Separation
Posted wangjunrui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1295E Permutation Separation相关的知识,希望对你有一定的参考价值。
[preface]
开一波E题闷声发大财
感谢@Karry5307 在考后提供思路
[description]
给定一个序列(p)(为1~n的排列),和这个序列每一个数所对应的花费a以及序列的长度n。
取一数(1leq k<n),将(p)序列分成两个序列,分别是(p_1,p_2,...,p_k)和(p_{k+1},p_{k+2},...,p_n)
将两个序列的某些数移到另一个序列使得第一个序列的所有数小于第二个序列的所有数,注意如果其中一组为空,则满足此条件,移动(p_i)的花费是(a_i)
求最小花费
[solution]
一道裸的线段树
考虑维护(a_i)的前缀和(sum_i=sum_{j=1}^{i}a_i),因为(1leq k<n),所以前缀和(sum)最多只要维护到(a_{n-1})即可
假设第一个序列的所有数都移到了第二个序列值最小虽然不大可能则
答案是(sum)中的最小值
因为(p)序列是1~n的排列,所以记(pos_i)为(i)在序列(p)中出现的位置
枚举i从1~n
假设将(p[pos_i])最终在第一序列,那么(p[pos_1],p[pos_2],...,,p[pos_{i-1}]一定在最终在第一序列),考虑当前对前缀和的修改。
当(k>=pos_i)时,(p[pos_i])在第一序列,那么不需要费用
当(k<pos_i)时,(p[pos_i])在第二序列,需要(a[pos_i])的费用移动到第一序列
则将(sum_1)~(sum_{pos_i-1})的值分别加上(a[pos_i])
(sum_{pos_i})~(sum_{n-1})的值分别减去(a[pos_i])
当前策略最小值即当前(sum)的最小值。
答案即是对所有策略的最小值取最小值
[code]
#include <cstdio>
#include <algorithm>
#define re register
#define ll long long
#define lc (root<<1)
#define rc (root<<1|1)
using namespace std;
template<typename T>
inline void read(T&x)
{
x=0;
char s=(char)getchar();
bool flag=false;
while(!(s>='0'&&s<='9'))
{
if(s=='-')
flag=true;
s=(char)getchar();
}
while(s>='0'&&s<='9')
{
x=(x<<1)+(x<<3)+s-'0';
s=(char)getchar();
}
if(flag)
x=(~x)+1;
return;
}
const int N=2e5+5;
struct Tree
{
ll minn,lazy;
} tree[N<<2];
ll sum[N];
inline void build(int root,int l,int r)
{
if(l==r)
{
tree[root].minn=sum[l];
tree[root].lazy=0;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
tree[root].minn=min(tree[lc].minn,tree[rc].minn);
return;
}
inline void pushdown(int root)
{
if(!tree[root].lazy)
return;
tree[lc].minn+=tree[root].lazy;
tree[rc].minn+=tree[root].lazy;
tree[lc].lazy+=tree[root].lazy;
tree[rc].lazy+=tree[root].lazy;
tree[root].lazy=0;
return;
}
inline void change(int root,int l,int r,int x,int y,int val)
{
if(r<x||l>y)
return;
if(x<=l&&r<=y)
{
tree[root].minn+=val;
tree[root].lazy+=val;
return;
}
int mid=(l+r)>>1;
pushdown(root);
change(lc,l,mid,x,y,val);
change(rc,mid+1,r,x,y,val);
tree[root].minn=min(tree[lc].minn,tree[rc].minn);
return;
}
int n,p[N],a[N],pos[N];
ll ans;
int main()
{
read(n);
for(re int i=1; i<=n; ++i)
{
read(p[i]);
pos[p[i]]=i;
}
for(re int i=1; i<=n; ++i)
{
read(a[i]);
sum[i]=sum[i-1]+a[i];
}
build(1,1,n-1);
ans=tree[1].minn;
for(re int i=1; i<=n; ++i)
{
change(1,1,n-1,1,pos[i]-1,a[pos[i]]);
change(1,1,n-1,pos[i],n-1,-a[pos[i]]);
// printf("%d
",ans);
ans=min(ans,tree[1].minn);
}
printf("%lld
",ans);
return 0;
}
以上是关于CF1295E Permutation Separation的主要内容,如果未能解决你的问题,请参考以下文章
[Codeforces 1295E]Permutation Separation(线段树+贪心)
Square Root of Permutation - CF612E