What Goes Up Must Come Down(变成山峰数组最小步数)
题目大意:
题意:给定 n 个整数的数组,通过移动相邻两个整数,使得这个数组构成一个单峰数组(前面非递减,后面非递增),求最少的移动次数。
题目解析:
分析:小的数一定在两边(要么左边,要么右边),所以可以从小到大判定所有数是移到左边移动次数少还是右边,树状数组维护一下就好了。
#include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long ll; const int maxn=1e6+100; int n; ll c[maxn],a[maxn]; vector<int>v[maxn]; int lowbit(int x){ return x&-x; } void add(int x,ll k){ for(int i=x;i<=n;i+=lowbit(i)){ c[i]+=k; } } ll query(int x){ ll ans=0; for(int i=x;i>0;i-=lowbit(i)){ ans+=c[i]; } return ans; } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; v[a[i]].push_back(i); add(i,1); } ll ans=0; int z=n; for(int i=1;i<=1e5;i++){ if(v[i].size()==0){ continue; } for(int j=0;j<v[i].size();j++){ add(v[i][j],-1);//把这个数的贡献减掉 z--;//数的总个数 } for(int j=0;j<v[i].size();j++){ ans+=min(z-query(v[i][j]),query(v[i][j]-1));//移动到左边或者右边 } } cout<<ans<<endl; }

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号