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

【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;
}
posted @ 2019-03-06 22:20  小蒟蒻yyb  阅读(365)  评论(3编辑  收藏  举报