bzoj1786: [Ahoi2008]Pair 配对&&1831: [AHOI2008]逆序对

一个自以为很对的东西,我们往-1放的数肯定是不增的。

然后就预处理一下,假如i这个位置放j会多多少逆序对。

DP一下,我的复杂度应该是O(n*m^2)的,然而你随便搞都能省掉一个m吧,我算了算好像可以过就不管了。

注意树状数组的时候getsum是a[i]-1,相同是不算逆序对的

#include<cstdio> 
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int s[110];
int lowbit(int x){return x&-x;}
void change(int x,int k)
{
    while(x<=100)
    {
        s[x]+=k;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=s[x];
        x-=lowbit(x);
    }
    return ret;
}

//-----------bit-求逆序对-------------------

int a[11000];
int c[11000][110];

int f[11000][110];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int _know=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]!=-1)
            _know++, change(a[i],1);
        else
            for(int j=1;j<=m;j++)c[i][j]=_know-getsum(j);
    }
    memset(s,0,sizeof(s));
    int ans=0;
    for(int i=n;i>=1;i--)
    {
        if(a[i]!=-1)
        {
            ans+=getsum(a[i]-1);
            change(a[i],1);
        }
        else
            for(int j=1;j<=m;j++)c[i][j]+=getsum(j-1);
    }
    
    //--------init-------------
    
    memset(f,63,sizeof(f));f[1][1]=0;    
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i]!=-1)
            {
                f[i][j]=f[i-1][j];
            }
            else
            {
                for(int k=1;k<=j;k++)
                    f[i][j]=min(f[i][j],f[i-1][k]+c[i][j]);
            }
        }
    }
    int ss=(1<<30);
    for(int j=1;j<=m;j++)ss=min(ss,f[n][j]);
    printf("%d
",ans+ss);
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/9040519.html