XJTUOJ wmq的队伍(树状数组求 K 元逆序对)

题目链接:http://oj.xjtuacm.com/problem/14/【分析】二元的逆序对应该都会求,可以用树状数组。这个题要求K元,我们可以看成二元的。我们先从后往前求二元逆序对数,

 然后对于每一个数就可以求出在这个数后面的比他小的数的数量。然后我们再加一元时,当前扫到a[i],那么在树状数组中,对于那些比他大的数的 逆序对数+=上一元a[i]的逆序对数。

#include <bits/stdc++.h>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long ll;
ll mod = 1e9+7;
const int N=2e4+50;
const int M=N*N+10;
int n,m,k,a[N];
ll tre[N],ans1[N],ans2[N];
void add(int x,ll s){
    while(x<=n){
        tre[x]+=s;
        tre[x]%=mod;
        x+=lowbit(x);
    }
}
ll Sum(int x){
    ll ret=0;
    while(x>0){
        ret+=tre[x];
        ret%=mod;
        x-=lowbit(x);
    }
    return ret;
}
int main() {
    int u,v;
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),ans2[i]=1;
        if(m==1){
            printf("%d
",n);continue;
        }
        for(int t=2;t<=k;t++){
            for(int i=1;i<=n;i++)ans1[i]=ans2[i],ans2[i]=tre[i]=0;
            for(int i=n;i>=1;i--){
                ans2[a[i]]=Sum(a[i]);
                add(a[i],ans1[a[i]]);
            }
        }
        ll ans=0;
        for(int i=1;i<=n;i++)ans=(ans+ans2[i])%mod;
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jianrenfang/p/6710162.html