zoukankan      html  css  js  c++  java
  • BZOJ1786 [Ahoi2008]Pair 配对 动态规划 逆序对

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1786


    题意概括

      给出长度为n的数列,只会出现1~k这些正整数。现在有些数写成了-1,这些-1可以变成任何数。

      求把这些-1变成1~k中的正整数之后,最少的逆序对个数为多少。


    题解

      我们可以判断,这些-1中写的数字一定是单调不降的。

      为什么?我们把答案序列的所有-1位抽出来,如果答案序列中有一组是逆序的,那么交换他们,一定可以保证小的那个换到大的那个的位置的时候,它左右产生的逆序对数一定比大的原先不多,同理,大的在原先的小的的位置上,产生的逆序对数也比原来小的不多。交换他们,本身就会减少一个逆序对,那么一定是更优的。

      所以我们确定了一定是单调不降的。

      那么这些-1位之间也不会有逆序对。

      那么就是一个简单的dp了。

      设dp[i][j]表示前i位,填到了j这个数,最少的逆序对数。注意这里的逆序对数是指-1中的数添入之后产生的逆序对数。

      然后取一个最小值,作为所有-1位产生的最少逆序对数。

      然后加上原来有的数产生的逆序对数就可以了。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=10000+5,M=100+5;
    int n,m,a[N],sml[N][M],big[N][M],tot[N][M],rot[N][M],dp[N][M];
    int main(){
    	scanf("%d%d",&n,&m);
    	memset(tot,0,sizeof tot);
    	memset(rot,0,sizeof rot);
    	memset(sml,0,sizeof sml);
    	memset(big,0,sizeof big);
    	memset(dp,0,sizeof dp);
    	for (int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		for (int j=1;j<=m;j++)
    			tot[i][j]=tot[i-1][j];
    		if (a[i]!=-1)
    			tot[i][a[i]]++;
    		for (int j=m;j>=1;j--)
    			big[i][j]=big[i][j+1]+tot[i][j];
    	}
    	for (int i=n;i>=1;i--){
    		for (int j=1;j<=m;j++)
    			rot[i][j]=rot[i+1][j];
    		if (a[i]!=-1)
    			rot[i][a[i]]++;
    		for (int j=1;j<=m;j++)
    			sml[i][j]=sml[i][j-1]+rot[i][j];
    	}
    	int tot=0;
    	for (int i=1;i<=n;i++){
    		int Min=1<<28;
    		if (a[i]!=-1)
    			tot+=big[i-1][a[i]+1]+sml[i+1][a[i]-1];
    		for (int j=1;j<=m;j++){
    			if (a[i]!=-1){
    				dp[i][j]=dp[i-1][j];
    				continue;
    			}
    			Min=min(Min,dp[i-1][j]);
    			dp[i][j]=Min+big[i-1][j+1]+sml[i+1][j-1];
    		}
    	} 
    	int ans=1<<28;
    	for (int i=1;i<=m;i++)
    		ans=min(ans,dp[n][i]);
    	printf("%d",ans+tot/2);
    	return 0;
    }
    

      

  • 相关阅读:
    数据结构学习记录_2019.02.26
    数据结构学习记录_2019.02.23
    数据结构学习记录_2019.02.27
    C语言学习记录_2019.02.23
    本博客所有博文密码均为“000000”
    Oracle触发器
    Oracle重载
    Oracle程序包
    Oracle函数
    Oracle存储过程
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1786.html
Copyright © 2011-2022 走看看