bzoj1786: [Ahoi2008]Pair 配对&&1831: [AHOI2008]逆序对
一个自以为很对的东西,我们往-1放的数肯定是不增的。
然后就预处理一下,假如i这个位置放j会多多少逆序对。
DP一下,我的复杂度应该是O(n*m^2)的,然而你随便搞都能省掉一个m吧,我算了算好像可以过就不管了。
注意树状数组的时候getsum是a[i]-1,相同是不算逆序对的
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int s[110]; int lowbit(int x){return x&-x;} void change(int x,int k) { while(x<=100) { s[x]+=k; x+=lowbit(x); } } int getsum(int x) { int ret=0; while(x>0) { ret+=s[x]; x-=lowbit(x); } return ret; } //-----------bit-求逆序对------------------- int a[11000]; int c[11000][110]; int f[11000][110]; int main() { int n,m; scanf("%d%d",&n,&m); int _know=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]!=-1) _know++, change(a[i],1); else for(int j=1;j<=m;j++)c[i][j]=_know-getsum(j); } memset(s,0,sizeof(s)); int ans=0; for(int i=n;i>=1;i--) { if(a[i]!=-1) { ans+=getsum(a[i]-1); change(a[i],1); } else for(int j=1;j<=m;j++)c[i][j]+=getsum(j-1); } //--------init------------- memset(f,63,sizeof(f));f[1][1]=0; for(int i=2;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i]!=-1) { f[i][j]=f[i-1][j]; } else { for(int k=1;k<=j;k++) f[i][j]=min(f[i][j],f[i-1][k]+c[i][j]); } } } int ss=(1<<30); for(int j=1;j<=m;j++)ss=min(ss,f[n][j]); printf("%d\n",ans+ss); return 0; }
pain and happy in the cruel world.