【BZOJ1831】[AHOI2008]逆序对(动态规划)

本文介绍了解决BZOJ1831[AHOI2008]逆序对问题的动态规划方法,通过设置状态f[i][j]表示填到位置i且上一个数为j时的最小逆序对数,利用预处理数组进行快速转移,最终求得最小逆序对总数。

【BZOJ1831】[AHOI2008]逆序对(动态规划)

题面

BZOJ
洛谷

题解

显然填入的数拎出来是不降的。
那么就可以直接大力\(dp\)
\(f[i][j]\)表示当前填到了\(i\),上一个填的数是\(j\)的最小逆序对数。
随便拿什么维护一下转移就好了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 10010
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int n,K,sum,a[MAX],ans=1e9,f[MAX][101],s1[101],s2[101];
int main()
{
    n=read();K=read();
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i)if(~a[i])s2[a[i]]+=1;
    for(int i=1;i<=K;++i)s2[i]+=s2[i-1];
    for(int i=1;i<=K;++i)s1[i]=s2[i];
    for(int i=1;i<=n;++i)
        if(~a[i])
        {
            sum+=s1[a[i]-1];
            for(int j=a[i];j<=K;++j)s1[j]-=1;
        }
    for(int i=1;i<=n;++i)
        if(~a[i])
        {
            for(int j=1;j<=K;++j)f[i][j]=f[i-1][j];
            for(int j=a[i];j<=K;++j)s2[j]-=1,s1[j]+=1;
        }
        else
        {
            for(int j=1;j<=K;++j)f[i][j]=f[i-1][j]+s2[j-1]+s1[K]-s1[j];
            for(int j=1;j<K;++j)f[i][j+1]=min(f[i][j+1],f[i-1][j]+s2[j]+s1[K]-s1[j+1]);
            for(int j=2;j<=K;++j)f[i][j]=min(f[i][j],f[i][j-1]);
        }
    for(int i=1;i<=K;++i)ans=min(ans,f[n][i]);
    printf("%d\n",ans+sum);
    return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/10486547.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值