1831: [AHOI2008]逆序对

来源:互联网 发布:大数据与云计算 编辑:程序博客网 时间:2024/05/16 15:47

题目大意:在填充一列数,使逆序对数最小。

有个结论,即当i<j且a[i]>a[j]时,将i,j调换一定更优。

所以填进去的数一定是不下降的。

然后树状数组一阵乱搞+dp就可以了。

调试笔记:树状数组边界要清楚。

code:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#define LL long longusing namespace std;const int inf(1<<28);int n,k,f[10010][110],num=0,a[10010],cost[10010][110],ans=0;int tr[3][110];int lowbit(int x){return x&(-x);}void change(int root,int K,int c){    for(int i=K;i<=k;i+=lowbit(i))        tr[root][i]+=c;}int getsum(int root,int k){    int ans=0;    for(int i=k;i>=1;i-=lowbit(i))        ans+=tr[root][i];    return ans;}int get(int root,int l,int r){    if(l>r) return 0;    return getsum(root,r)-getsum(root,l-1);}int main(){    scanf("%d %d",&n,&k);    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        if(a[i]!=-1) change(0,a[i],1),ans+=get(0,a[i]+1,k);    }    for(int i=1;i<=n;i++)    {        if(a[i]!=-1) change(0,a[i],-1),change(1,a[i],1);        else        {            num++;            for(int j=1;j<=k;j++) cost[num][j]=get(1,j+1,k)+getsum(0,j-1);        }    }    if(num==0){printf("%d",ans);return 0;}    for(int i=1;i<=num;i++) f[i][0]=inf;    for(int i=1;i<=num;i++)        for(int j=1;j<=k;j++)                f[i][j]=min(f[i][j-1],f[i-1][j]+cost[i][j]);    printf("%d",ans+f[num][k]);}