您的位置:首页 > 其它

bzoj 4240: 有趣的家庭菜园

2018-03-14 22:05 218 查看

题意:

给出一个序列,问你最少交换多少次相邻的数,使这个序列变成单峰的。

题解:

这题其实不难,但想了很久,关键是要想到怎么贪。

考虑从小到达插入数,显然是向两边移,贪心取较小步数的是最优的大概意会下显然是对的那么可以树状数组为胡每个数当前位置。

注意相同的数要一起处理,wa了几发。

总结:

遇到这种序列题可以考虑按一定顺序插入。

code:

#include<map>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
struct node{
int a,x;
}h[300010];
int n,tr[300010],l=0,r=0;
void change(int k,int c) {for(int i=k;i<=n;i+=i&-i) tr[i]+=c;}
int get(int k) {int ans=0;for(int i=k;i>=1;i-=i&-i) ans+=tr[i];return ans;}
bool cmp1(node a,node b) {return a.a==b.a?a.x<b.x:a.a<b.a;}
bool cmp2(node a,node b) {return a.x>b.x;}
LL ans=0;
void solve(int L,int R)
{
while(L<=R)
{
int k=h[L].x+get(h[L].x);
if(k-1-l<n-k-r-(R-L)) ans+=(LL)(k-1-l),l++,change(1,1),change(h[L].x,-1);
else break;
L++;
}
if(L<=R)
{
sort(h+L,h+R+1,cmp2);
while(L<=R)
{
int k=h[L].x+get(h[L].x);
ans+=(LL)(n-k-r);r++;change(h[L].x,-1);L++;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&h[i].a),h[i].x=i;
sort(h+1,h+n+1,cmp1);
int p=1;
while(p<=n)
{
int L=p;
while(p<n&&h[p].a==h[p+1].a) p++;
solve(L,p);p++;
}
printf("%lld",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: