【BZOJ】1831: [AHOI2008]逆序对
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1831
考虑$-1$的位置上填写的数字一定是不降的。
令${f[i][j]}$表示$DP$到了第$i$位,最后一个$-1$上填的数字是$j$的最少逆序对数量。
如果当前位置是$-1$:
${f[i][j]=min\left \{ f[i-1][x] |x\leq j \right \}+ma[i][j+1]+mi[i][j-1]}$
如果当前位是确定的数字。
${f[i][j]=f[i-1][j]+ma[i][j+1]}$
其中${ma[i][j]}$表示在给定数组第$i$位之前的数字中大于等于$j$的数字的数量,${mi[i][j]}$表示在给定数组第$i$位之后的数字中小于等于$j$的数字的数量。
${ma,mi}$数组用树状数组维护一下即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 10010 10 #define llg long long 11 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 12 llg n,m,f[maxn][110],val[maxn],V[maxn]; 13 llg c[maxn]; 14 15 llg lowbit(llg x){return x&-x;} 16 17 void add(llg x,llg v){for (;x<=m;x+=lowbit(x)) val[x]+=v;} 18 19 llg sum(llg x){llg tot=0; for (;x>0;x-=lowbit(x)) tot+=val[x]; return tot;} 20 21 void add_(llg x,llg v){for (;x<=m;x+=lowbit(x)) V[x]+=v;} 22 23 llg sum_(llg x){llg tot=0; for (;x>0;x-=lowbit(x)) tot+=V[x]; return tot;} 24 25 int main() 26 { 27 yyj("bzoj1831"); 28 cin>>n>>m; 29 for (llg i=0;i<=n;i++) 30 for (llg j=0;j<=m;j++) 31 f[i][j]=0x7fffffff; 32 for (llg i=1;i<=n;i++) 33 { 34 scanf("%lld",&c[i]); 35 if (c[i]!=-1) add_(c[i],1); 36 } 37 f[0][0]=0; 38 for (llg i=1;i<=n;i++) 39 { 40 if (c[i]!=-1) 41 { 42 for (llg j=0;j<=m;j++) f[i][j]=f[i-1][j]+sum(m)-sum(c[i]); 43 add_(c[i],-1); 44 add(c[i],1); 45 } 46 else 47 { 48 llg mi=f[i-1][0]; 49 for (llg j=1;j<=m;j++) 50 { 51 mi=min(f[i-1][j],mi); 52 f[i][j]=mi+sum(m)-sum(j)+sum_(j-1); 53 } 54 } 55 } 56 llg ans=0x7fffffff; 57 for (llg i=0;i<=m;i++) ans=min(ans,f[n][i]); 58 cout<<ans; 59 return 0; 60 }
本文作者:xrdog
作者博客:http://www.cnblogs.com/Dragon-Light/
转载请注明出处,侵权必究,保留最终解释权!