BZOJ1786: [Ahoi2008]Pair 配对/1831: [AHOI2008]逆序对
这两道题是一样的。
可以发现,-1变成的数是单调不降。
记录下原有的逆序对个数。
预处理出每个点取每个值所产生的逆序对个数,然后dp转移。
#include<cstring> #include<iostream> #include<cstdio> #include<map> #include<cmath> #include<algorithm> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define low(x) (x&(-x)) #define maxn 10050 #define inf 2000000000 #define mm 1000000007 using namespace std; int f[maxn][105],a[maxn],t[maxn],pos[maxn],c[maxn][105]; int now,n,k,cnt,ans; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void add(int x,int y){ while (x<=k){ t[x]=t[x]+y; x+=low(x); } } int ask(int x){ int ans=0; while (x){ ans+=t[x]; x-=low(x); } return ans; } int main(){ n=read(); k=read(); rep(i,1,n){ a[i]=read(); if (a[i]!=-1){ ans+=ask(k)-ask(a[i]); add(a[i],1); } else { pos[++cnt]=i; rep(j,1,k) c[i][j]+=ask(k)-ask(j); } } clr(t,0); down(i,n,1){ if (a[i]!=-1) add(a[i],1); else { rep(j,1,k) c[i][j]+=ask(j-1); } } rep(i,1,cnt) rep(j,0,k) f[i][j]=inf; rep(i,1,cnt){ int now=pos[i]; rep(j,1,k) f[i][j]=min(f[i][j-1],f[i-1][j]+c[now][j]); } printf("%d\n",f[cnt][k]+ans); return 0; }