1831: [AHOI2008]逆序对

Description

小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远。好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间。如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为一个“逆序对”。你数一数下面的数字里有多少个逆序对,你就知道Y岛离这里的距离是多少千米了。 比如说,4 2 1 3 3里面包含了5个逆序对:(4, 2), (4, 1), (4, 3), (4, 3), (2, 1)。 可惜的是,由于年代久远,这些数字里有一部分已经模糊不清了,为了方便记录,小可可用“-1”表示它们。比如说,4 2 -1 -1 3 可能原来是4 2 1 3 3,也可能是4 2 4 4 3,也可能是别的样子。 小可可希望知道,根据他们看清楚的这部分数字,能不能推断出这些数字里最少能有多少个逆序对。

Input

第一行两个正整数N和K。第二行N个整数,每个都是-1或是一个在1~K之间的数。

Output

一个正整数,即这些数字里最少的逆序对个数。

Sample Input

5 4
4 2 -1 -1 3

Sample Output

4

HINT

4 2 4 4 3中有4个逆序对。当然,也存在其它方案得到4个逆序对。

数据范围:
100%的数据中,N<=10000,K<=100。
60%的数据中,N<=100。
40%的数据中,-1出现不超过两次。

 
这道题应该很容易想到填的数至少是递增的。。。其实我并不会证明=,=
口胡一下就是,两个数a>b,a在前b在后。。。如果交换a和b,那么a前面和b后面的逆序对个数不会变化,
a和b之间的逆序对最差是不变的,因为一个更小的数放在了前面,一个更大的数放在了后面,
所以可以发现递增的填入数字是最优的,那么就可以发现前面填过的数字对后面填什么并没有影响。。。
所以就可以用DP搞一搞了。。。
用F[i][j]表示第i个空填的数字为j,所产生的逆序对。。。
那么就可以得到F[i][j]=min(F[i][j],F[i-1][p]+cost[i][j])
cost[i][j]就是第i位填j所产生的逆序对数,可以预处理出来每一位填一个数所产生的逆序对个数(我感觉这个真是太神辣。。。没看数据的话,这么暴力的预处理真的不会T吗。。。)
然后就可以做了,答案要记得加上原先的逆序对个数。。
 4 #include<iostream>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 #include<cstdio>
 9 #include<algorithm>
10 #include<string>
11 #include<map>
12 #include<queue>
13 #include<vector>
14 #include<set>
15 #define inf 1000000000
16 #define maxn 10000+5
17 #define maxm 100+5
18 #define eps 1e-10
19 #define ll long long
20 #define for0(i,n) for(int i=0;i<=(n);i++)
21 #define for1(i,n) for(int i=1;i<=(n);i++)
22 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
23 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
24 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
25 using namespace std;
26 int a[maxn],p[maxn],tot;
27 ll f[maxn][maxm],big[maxn][maxm],g[maxn][maxm],sma[maxn][maxm];
28 int read(){
29     int x=0,f=1;char ch=getchar();
30     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
31     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
32     return x*f;
33 }
34 int main(){
35     //freopen("input.txt","r",stdin);
36     //freopen("output.txt","w",stdout);
37     int n=read(),k=read();
38     for1(i,n){
39         a[i]=read();
40         if(a[i]==-1)tot++,p[tot]=i;
41     }
42     for(int i=1;i<=n;i++){
43         for(int j=1;j<=k;j++){
44             big[i][j]=big[i-1][j];
45             if(a[i]>j) big[i][j]++;
46         }
47     }
48     for(int i=n;i>=1;i--){
49         for(int j=1;j<=k;j++){
50             sma[i][j]=sma[i+1][j];
51             if((a[i]<j)&&(a[i]!=-1)) sma[i][j]++;
52         }
53     }
54     for1(i,tot){
55         f[i][1]=f[i-1][1]+big[p[i]][1]+sma[p[i]][1];
56         g[i][1]=f[i][1];
57         for2(j,2,k){
58             f[i][j]=g[i-1][j]+big[p[i]][j]+sma[p[i]][j];
59             g[i][j]=min(g[i][j-1],f[i][j]);
60         }
61     }
62     ll ans=inf;
63     for1(i,k){
64         ans=min(ans,f[tot][i]);
65     }
66     for1(i,n)ans+=big[i][a[i]];
67     cout<<ans;
68     return 0;
69 }
View Code

 

posted @ 2016-02-11 16:05  HTWX  阅读(261)  评论(0编辑  收藏  举报