BZOJ1831: [AHOI2008]逆序对
1831: [AHOI2008]逆序对
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 341 Solved: 226
[Submit][Status]
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出现不超过两次。
Source
题外话:
{
刚开始看错题了,看成100%数据-1不超过2个,于是想这不是sb暴力吗?于是就开始敲代码,敲完之后就悲剧了。。。
结果发现不会做。。。
一看题解忽然明白了,我靠怎么还有这样一个性质,那就是 DP了。。。自己想的时候没想到DP QAQ。。。
}
题解:考虑一般情况 -1有很多,爆搜就不行了,那么应该如何下手呢?
联想学过的知识,大概只有DP可以用了
但怎么DP呢?
这些填的数应该有什么性质---一列数能有什么性质?大概就是递增递减吧。。。
(吐槽:这思路也太牵强了吧。。。回答:。。。。。。)
下面我们考虑两个空 a,b ,分别填上了x,y (假设只有两个空,并且x>y)
如果我们交换 x 和 y 那么会有这样几条性质:
1.[1,a-1],[b+1,n]中的数与x,y构成的逆序对没有发生改变
2.[a+1,b-1]中 >max(x,y)的数与x,y构成的逆序对没有发生改变
3.[a+1,b-1]中 < min(x,y)的数与x,y构成的逆序对没有发生改变
4.[a+1,b-1]中处于区间(x,y)的数不再与x,y构成逆序对
5.x,y不再构成逆序对
也就是说我们交换x,y得到的答案一定会减小!
稍微推广一下就是 这些填的数单调递增,但不一定是严格的
考虑实现
for i=1 to n do
for j=1 to k do
for p=1 to j do
f[i,j]=min(f[i,j],f[i-1,p]+cost(i,j))
NO NO NO
既然考虑到cost(i,j)是固定的,我们只需要求f[i-1,1],f[i-1,2]......f[i-1,j]的最小值即可
前缀最小值优化!类似于前缀和。。。
这样状态数一共有O(N*K)个,每个状态的转移的复杂度为O(1)
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 var f,g,big,sma:array[0..150000,0..150] of longint; 2 ans,i,j,n,tot,k:longint; 3 a,b:array[0..150000] of longint; 4 function min(x,y:longint):longint; 5 begin 6 if x<y then exit(x) else exit(y); 7 end; 8 procedure init; 9 begin 10 readln(n,k);tot:=0; 11 for i:=1 to n do 12 begin 13 read(a[i]); 14 if a[i]=-1 then begin inc(tot);b[tot]:=i;end; 15 end; 16 end; 17 procedure main; 18 begin 19 fillchar(big,sizeof(big),0); 20 for i:=1 to n do 21 for j:=1 to k do big[i,j]:=big[i-1,j]+ord(a[i]>j); 22 fillchar(sma,sizeof(sma),0); 23 for i:=n downto 1 do 24 for j:=1 to k do sma[i,j]:=sma[i+1,j]+ord((a[i]<j) and (a[i]<>-1)); 25 fillchar(f,sizeof(f),0); 26 for i:=1 to tot do 27 begin 28 f[i,1]:=f[i-1,1]+big[b[i],1]+sma[b[i],1]; 29 g[i,1]:=f[i,1]; 30 for j:=2 to k do 31 begin 32 f[i,j]:=g[i-1,j]+big[b[i],j]+sma[b[i],j]; 33 g[i,j]:=min(g[i,j-1],f[i,j]); 34 end; 35 end; 36 ans:=maxlongint; 37 for i:=1 to k do ans:=min(ans,f[tot,i]); 38 for i:=1 to n do inc(ans,big[i,a[i]]); 39 writeln(ans); 40 end; 41 begin 42 assign(input,'input.txt');assign(output,'output.txt'); 43 reset(input);rewrite(output); 44 init; 45 main; 46 close(input);close(output); 47 end. 48