BZOJ4240: 有趣的家庭菜园

来源:互联网 发布:电脑上写小说的软件 编辑:程序博客网 时间:2024/05/02 09:53

问移成一个前一段单调不降,后一段单调不升的序列最少要交换多少次
将原序列标一下下标,那么最终序列需要的交换次数就是其标号序列的逆序对数,比如从 2 8 4 5 3 6 -> 2 4 5 8 6 3 ,最终序列的下标分别是: 1 3 4 2 6 5,逆序对个数为3,所以至少交换3次
然后因为最高的一定放在中间,次高的在其两侧中的一侧,我们可以贪心的去构造这个最终序列。先把最高的放中间,然后放次高的,放哪边使目前的逆序对少就放哪边,因为次高的不管放左还是右,它对于之后放的是没有影响的,所以可以贪心


#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long long#define lowbit(x) x&(-x)using namespace std;const int maxn = 310000;struct node{    int i,x;}a[maxn];bool cmp(node x,node y){return x.x>y.x;}int n;ll s[maxn];void upd(int x){for(;x<=n;x+=lowbit(x))s[x]+=1;}ll query(int x){ll r=0;for(;x;x-=lowbit(x))r+=s[x];return r;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].i=i;    sort(a+1,a+n+1,cmp);    ll ret=0; a[n+1].x=a[n].x+1;    for(ll i=1;i<=n;)    {        ll j;        for(j=i;j<=n;j++)        {            ll r=query(a[j].i);            ret+=min(r,(ll)i-1-r);            if(a[j].x!=a[j+1].x) break;        }        for(;i<=j;i++) upd(a[i].i);    }    printf("%lld\n",ret);    return 0;}
0 0