zoukankan      html  css  js  c++  java
  • AtCoder ARC097C Sorted and Sorted:dp

    传送门

    题意

    有 $ 2n $ 个球排成一行,其中恰好有 $ n $ 个白球和 $ n $ 个黑球。每个球上写着数字,其中白球上的数字的并集为 $ lbrace 1 dots n brace $ ,黑球上的数字的并集也为 $ lbrace 1 dots n brace $ 。

    你可以交换任意两个相邻的球若干次,以使得对于所有白球,数字大小从左到右递增,黑球也是一样。

    问你最少的交换次数。$ (n leq 2000) $

    题解

    如果所有球最后的位置 $ P(i) $ 已经确定,那么最少交换次数 $ ans $ 为:

    [ans = sum_{i=1}^{2n} sum_{j=i+1}^{2n} [P(i) > P(j)] ]

    也就是相对位置改变了的球对 $ (i,j) $ 的个数。

    然后考虑如何dp。

    由于白球和黑球内部,数字大小递增,所以可以考虑从左到右依次填球。

    $ dp[i][j] $ 表示已经从左到右填了 $ i $ 个白球,$ j $ 个黑球,此时的最小代价。

    则最终答案就是 $ dp[n][n] $

    然后考虑如何转移。

    对于 $ dp[i][j] $ 来说,接下来要么填一个白球,要么填一个黑球。

    设 $ costw[i][j] $ 表示已经填了 $ i $ 个白球,$ j $ 个黑球,该填第 $ i+1 $ 个白球,会增加的代价。

    同理 $ costb[i][j] $ 表示已经填了 $ i $ 个白球,$ j $ 个黑球,该填第 $ j+1 $ 个黑球,会增加的代价。

    则有转移:

    [dp[i][j] = min(dp[i-1][j]+costw[i-1][j],dp[i][j-1]+costb[i][j-1]) ]

    边界条件为 $ dp[0][0] = 0 $

    dp的复杂度为 $ O(n^2) $

    对于 $ cost $ 数组来说,同样可以 $ O(n^2) $ 预处理。

    首先可以 $ O(n^2) $ 暴力处理出所有 $ cost[i][0] $ 和 $ costb[0][j] $

    设 $ P_w[i] $ 表示写着数字 $ i $ 的白球的初始位置,$ P_b[i] $ 表示写着数字 $ i $ 的黑球的初始位置。

    则对于 $ cost $ 数组来说,有如下递推:

    [costw[i][j] = costw[i][j-1] + [P_b[j] > P_w[i+1]] ]

    [costb[i][j] = costb[i-1][j] + [P_w[i] > P_b[j+1]] ]

    所以预处理总复杂度也是 $ O(n^2) $ 的。

    AC Code

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #define MAX_N 2005
    
    using namespace std;
    
    int n;
    int pw[MAX_N];
    int pb[MAX_N];
    int dp[MAX_N][MAX_N];
    int costw[MAX_N][MAX_N];
    int costb[MAX_N][MAX_N];
    
    void read()
    {
    	scanf("%d",&n);
    	char s[4]; int x;
    	for(int i=1;i<=(n<<1);i++)
    	{
    		scanf("%s%d",s,&x);
    		if(s[0]=='W') pw[x]=i;
    		else pb[x]=i;
    	}
    }
    
    void cal_c()
    {
    	for(int i=0;i<n;i++)
    	{
    		for(int j=1;j<=i;j++) costw[i][0]+=(pw[j]>pw[i+1]);
    		for(int j=1;j<=n;j++) costw[i][j]=costw[i][j-1]+(pb[j]>pw[i+1]);
    	}
    	for(int j=0;j<n;j++)
    	{
    		for(int i=1;i<=j;i++) costb[0][j]+=(pb[i]>pb[j+1]);
    		for(int i=1;i<=n;i++) costb[i][j]=costb[i-1][j]+(pw[i]>pb[j+1]);
    	}
    }
    
    void cal_dp()
    {
    	memset(dp,0x3f,sizeof(dp));
    	dp[0][0]=0;
    	for(int i=0;i<=n;i++)
    	{
    		for(int j=0;j<=n;j++)
    		{
    			if(i) dp[i][j]=min(dp[i][j],dp[i-1][j]+costw[i-1][j]);
    			if(j) dp[i][j]=min(dp[i][j],dp[i][j-1]+costb[i][j-1]);
    		}
    	}
    }
    
    void work()
    {
    	cal_c();
    	cal_dp();
    	printf("%d
    ",dp[n][n]);
    }
    
    int main()
    {
    	read();
    	work();
    }
    
  • 相关阅读:
    [Tips] kubeconfig合并
    某书补充题选做
    Card
    Ant Design Pro V5 使用 Cesium 地图开发包遇到加载widgets.css样式报错
    工作相关
    pc端谷歌浏览器长截图
    dao层与xml之间联系
    三周的大学生活,我到底是怎么过来的
    湖南大学推荐书《社会学大纲》阅读有感 其二
    湖南大学新生报到游记 其一
  • 原文地址:https://www.cnblogs.com/Leohh/p/9132410.html
Copyright © 2011-2022 走看看