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
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 }