bzoj 1831: [AHOI2008]逆序对

可以证明在-1的位置填的数是单调不降的。
看到数据范围n<=10000,k<=100就可以想到f[i][j]表示前i个数,最后一个-1的位置填的数<=j的逆序对数的最小值。
转移的时候,一个不是-1的位置贡献的逆序对数与它前面的-1的位置具体填了多少有关,所有考虑贡献提前计算,即如果这个位置是-1,把它前面和后面所有不是-1的位置形成的逆序对都计算进去,而不是-1的位置只需要把它和它后面不是-1的位置形成的逆序对计算进去(-1之间不会形成逆序对)。
然后,树状数组优化求逆序对即可(但是数据范围好小,直接暴力维护前缀和数组就行。)
    
    
    
    
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
using namespace std;
int f[10010][110],a[10010];
int L[110],R[110];
int main()
{
int n,K;
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if (a[i]>0) R[a[i]]++;
}
for (int i=1;i<=K;i++) R[i]+=R[i-1];
for (int i=1;i<=n;i++)
{
if (a[i]==-1)
{
f[i][0]=inf;
for (int j=1;j<=K;j++)
f[i][j]=min(f[i][j-1],f[i-1][j]+L[K]-L[j]+R[j-1]);
}
else
{
for (int j=a[i];j<=K;j++) R[j]--;
for (int j=1;j<=K;j++) f[i][j]=f[i-1][j]+R[a[i]-1];
for (int j=a[i];j<=K;j++) L[j]++;
}
}
printf("%d\n",f[n][K]);
return 0;
}

你可能感兴趣的:(bzoj 1831: [AHOI2008]逆序对)