Description
Input
Output
Sample Input
4 2 -1 -1 3
Sample Output
HINT
4 2 4 4 3中有4个逆序对。当然,也存在其它方案得到4个逆序对。
数据范围:
100%的数据中,N<=10000,K<=100。
60%的数据中,N<=100。
40%的数据中,-1出现不超过两次。
题解:
首先可以证明-1位置的数一定是单调不降的.
假设相邻的两个-1的位置是(x,y)(a[x]<=a[y]);
如果交换x,y;
对1-x和y-n中的数显然没有影响.
对x-y中大于max(a[x],a[y])和小于min(a[x],a[y])的数显然也没有影响.
但是对x-y中a[x]-a[y]的数,逆序对数显然增加了.
所以交换x,y只会导致逆序对数不降.
所以-1位置的数一定是单调不降的.
然后我们就不用考虑-1之间的逆序对数了.
预处理一下lc[i][j],rc[i][j]和初始答案.
lc[i][j]表示第i个-1选j左边增加的逆序对数.
rc[i][j]表示第i个-1选j右边增加的逆序对数.
然后设f[i][j]表示前i个-1,第i个-1选j最少的逆序对数.
做一个前缀最小值转移就可以做到O(NK)了.
最后答案就是ans+f[-1的个数][k];
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10010
#define M 110
using namespace std;
int f[N][M],a[N],p[N],n,m,ans,lc[N][M],rc[N][M],l,r,t;
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
if (a[i]!=-1){
for (int j=a[i]+1;j<=m;j++)
ans+=p[j];
p[a[i]]++;
}
else r++;
}
memset(p,0,sizeof(p));
for (int i=1;i<=n;i++)
if (a[i]==-1){
l++;lc[l][0]=t;
for (int j=1;j<=m;j++)
lc[l][j]=lc[l][j-1]-p[j];
}
else p[a[i]]++,t++;
memset(p,0,sizeof(p));t=0;
for (int i=n;i>=1;i--)
if (a[i]==-1){
rc[r][0]=0;
for (int j=1;j<=m;j++)
rc[r][j]=rc[r][j-1]+p[j-1];
r--;
}
else p[a[i]]++;
for (int i=1;i<=l;i++){
for (int j=1;j<=m;j++)
f[i][j]=f[i-1][m]+lc[i][j]+rc[i][j];
for (int j=2;j<=m;j++)
f[i][j]=min(f[i][j],f[i][j-1]);
}
cout<<f[l][m]+ans;
}