1800*2【Codeforces Round #612 (Div. 1) A】Garland

题目链接

链接

翻译

给你一个排列,其中有一些位置上的数字被remove了,让你全都放回去。

定义相邻两个数字如果奇偶性不同,\(diff\) 值加 \(1\)

求数字全都放回去之后 \(diff\) 的值的最小值。

题解

\(dp[i][j][k]\) 表示前 \(i\) 个数字放了 \(j\) 个偶数,最后一个数字奇偶性为 \(k\) 的最小 \(diff\)

之所以可以只用偶数的个数来定义前 \(i\) 个的状态,是因为它是一个排列。最后放完以后,偶数的个数是确定的。

而这个偶数具体是什么对我们这道题而言不影响。所以我们只要关注奇偶性就好。

至于会不会出现哪个地方放进去偶数然后其实没有足够的偶数让你用呢? 这种情况会被后面没被移走的偶数做转移的时候 exclude 掉的。

所以我们只要老老实实地记录 \(j\) 个偶数最好的情况就行,至于这个状态是不是合法的,没有关系的。

最后输出 \(dp[n][n/2][0]\)\(dp[n][n/2][1]\) 中较小者即可。

时间复杂度 \(\mathcal{O}(N^2)\)

代码

#include <bits/stdc++.h>
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define LL long long
using namespace std;

const int N = 100;

//dp[i][j][k] 前 i 个位置,偶数个数有 j 个,最后一个位置奇偶性为k最小diff
int dp[N+10][N+10][2];
int n,p[N+10];

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    memset(dp,255,sizeof dp);
    for (int i = 0;i <= N; i++){
        for (int j = 0;j <= N; j++){
            for (int k = 0;k < 2; k++){
                dp[i][j][k] = 1000;
            }
        }
    }
    dp[0][0][0] = dp[0][0][1] = 0;
    cin >> n;
    for (int i = 1;i <= n; i++){
        cin >> p[i];
        for (int j = 0;j <= i; j++){
            if (j>0 && p[i]%2 == 0){
                dp[i][j][0] = min(dp[i-1][j-1][1]+1,dp[i-1][j-1][0]);
            }
            if (p[i] == 0 || p[i]%2 == 1){
                dp[i][j][1] = min(dp[i-1][j][0]+1,dp[i-1][j][1]);
            }
        }
    }
    cout << min(dp[n][n/2][0],dp[n][n/2][1]) << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值