树状数组 hdu2689 hdu2838

题意:给定一个正整数n,和一个1-n的一个排列,每个数可以和旁边的两个数的任意一个交换,每交换一次总次数就要加一,问将这个排列转换成一个递增的排列需要多少次交换?

题意可以转换成求这个排列的逆序对数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=1e3+3;
int bit[M],n;
void update(int x,int c){
    while(x<=n)
        bit[x]+=c,x+=x&-x;
}
int sum(int x){
    int ans=0;
    while(x)
        ans+=bit[x],x-=x&-x;
    return ans;
}
int main(){
    while(~scanf("%d",&n)){
        int ans=0;
        memset(bit,0,sizeof(bit));
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            update(x,1);
            ans+=i-sum(x);//sum(x)表示小于等于x的总数,而i-sum()则表示大于x的总数,即为逆序数的总数
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 2838

题意:给定一序列,问排成升序所要求的最少代价,序列中俩俩可相交换,代价为俩者的和

分析:

对于每个数字x,我们只需要把它和前面比它大的数字交换,求出交换代价,重复执行就能得出答案。

这个代价就是,比它大的数字个数t*x+前面比它大的数字和。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int M=1e5+5;
ll cnt[M],sum[M],n;
void update(int x,int c1,int c2){
    while(x<=n){
        cnt[x]+=c2;
        sum[x]+=c1;
        x+=x&-x;
    }
}
ll cntt(int x){
    ll ans=0;
    while(x)
        ans+=cnt[x],x-=x&-x;
    return ans;
}
ll summ(int x){
    ll ans=0;
    while(x)
        ans+=sum[x],x-=x&-x;
    return ans;
}
int main(){
    while(~scanf("%d",&n)){
        for(int i=0;i<=n;i++)
            cnt[i]=0,sum[i]=0;
        ll ans=0;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            update(x,x,1);
            ans+=(i-cntt(x))*1ll*x*1ll+summ(n)-summ(x);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2019-07-13 22:00  starve_to_death  阅读(116)  评论(0编辑  收藏  举报