传送门
文章目录
- 题意:
- 思路:
题意:
给你一个打乱的排列,每个位置都各有一个价值,让你选择一个分界点,分成p1,p2,...,prp_1,p_2,...,p_rp1,p2,...,pr和pr+1,...,pn−1,pnp_{r+1},...,p_{n-1},p_{n}pr+1,...,pn−1,pn,两部分非空,可以将某一边的数花费代价aia_iai移动到另一边,当左边所有数都小于右边或者某一边为空的时候,符合条件,求符合条件的时候的最小代价。
思路:
先考虑暴力怎么写。
定义f[i][j]f[i][j]f[i][j]表示以iii为分割点,[1,i][1,i][1,i]在左边,[i+1,n][i+1,n][i+1,n]在右边,让后通过移动使得a[1,i]<=j,a[i+1,n]>ja_{[1,i]}<=j,a_{[i+1,n]}>ja[1,i]<=j,a[i+1,n]>j的最小代价是f[i][j]f[i][j]f[i][j],初始状态f[0][k]=∑i=1kbif[0][k]=\sum _{i=1}^{k}b_if[0][k]=∑i=1kbi(注意bbb是排序后iii这个位置的花费),转移也比较好写了:f[i][k]=f[i−1][k]−a[i]k∈[p[i],n]f[i][k]=f[i-1][k]-a[i] \ \ k\in [p[i],n]f[i][k]=f[i−1][k]−a[i] k∈[p[i],n]f[i][k]=f[i−1][k]+a[i]k∈[1,p[i]−1]f[i][k]=f[i-1][k]+a[i] \ \ k\in [1,p[i]-1]f[i][k]=f[i−1][k]+a[i] k∈[1,p[i]−1]
对于第一个方程的解释为当k∈[p[i],n]k\in [p[i],n]k∈[p[i],n]的时候,原本iii需要花费a[i]a[i]a[i]移动到左边,但是由于分割点右移,所以不需要花费a[i]a[i]a[i],所以应该减掉。
对于第二个方程解释为当k∈[1,p[i]−1]k\in [1,p[i]-1]k∈[1,p[i]−1]的时候,原本iii不需要花费a[i]a[i]a[i]到右边,因为本来就在右边,但是分割点右移之后他到左边了,所以需要花费a[i]a[i]a[i],应该加上。
但是这个方程的转移是O(N2)O(N^2)O(N2)的,我们考虑用线段树来实现区间加,让后维护一个minminmin,最后直接取tr[1].mintr[1].mintr[1].min即可。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n;
int p[N],a[N];
struct Tree
{struct Node{int l,r;LL mi,lazy;}tr[N<<2];void pushup(int u){tr[u].mi=min(tr[L].mi,tr[R].mi);}void pushdown(int u){if(tr[u].lazy==0) return;LL lazy=tr[u].lazy; tr[u].lazy=0;tr[L].lazy+=lazy; tr[L].mi+=lazy;tr[R].lazy+=lazy; tr[R].mi+=lazy;}void build(int u,int l,int r){tr[u]={l,r,0,0};if(l==r) { tr[u].mi=0; return; }build(L,l,Mid); build(R,Mid+1,r);}void modify(int u,int l,int r,int x){if(tr[u].l>=l&&tr[u].r<=r){tr[u].mi+=x;tr[u].lazy+=x;return;}pushdown(u);if(l<=Mid) modify(L,l,r,x);if(r>Mid) modify(R,l,r,x);pushup(u);}
}x;int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&p[i]);for(int i=1;i<=n;i++) scanf("%d",&a[i]);LL ans=min(a[1],a[n]);x.build(1,1,n);for(int i=1;i<=n;i++) x.modify(1,p[i],n,a[i]);for(int i=1;i<=n-1;i++){x.modify(1,1,p[i]-1,a[i]);x.modify(1,p[i],n,-a[i]);ans=min(ans,x.tr[1].mi);}printf("%lld\n",ans);return 0;
}