BZOJ4240: 有趣的家庭菜园
4240: 有趣的家庭菜园
https://www.lydsy.com/JudgeOnline/problem.php?id=4240
Sol.
最终的序列一定是一个山峰的形状。
从小到大枚举每一个数,此时只考虑比它大的数(比它小的已经排好)
那么它(x)的贡献就是min(id<x,id>x) 也就是放到左边和放到右边的代价。
这样贪心是互不影响的。
注意数值相等的不会贡献,先删除再查询就行
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define maxn 300005 using namespace std; int n,tr[maxn]; struct node{ int h,id; }s[maxn]; bool cmp(node a,node b){return a.h<b.h;} void add(int x,int v){ for(int i=x;i<=n;i+=i&-i)tr[i]+=v; } int ask(int x){ int sum=0;for(int i=x;i;i-=i&-i)sum+=tr[i];return sum; } int main(){ cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&s[i].h),s[i].id=i; add(s[i].id,1); } sort(s+1,s+n+1,cmp); int cnt=n;long long ans=0; for(int i=1;i<=n;i++){ int j; for(j=i;s[j].h==s[i].h&&j<=n;j++)add(s[j].id,-1),cnt--; for(j=i;s[j].h==s[i].h;j++){ int x=ask(s[j].id); // cout<<s[j].id<<' '<<x<<' '<<cnt<<endl; ans+=min(x,cnt-x); } i=j-1; } cout<<ans<<endl; return 0; }