Educational Codeforces Round 128 (Rated for Div. 2)

D

鸽.....

E

给一个2*n的网格,一些(至少一个)网格上面存在一个物品,当两个物品移动到同一个网格的时候变成一个
每次可以移动一个物品,求移动的最小次数
首先求出存在物品的列区间为[l, r]
显然存在,不会将物品移动到[l, r]之外
在[l, r]之间做dp
f[i][0]:表示从l列移动到第i列,并且停在了第一行
f[i][1]:表示从l列移动到第i列,并且停在了第二行
状态转移:根据第i列物品的状态以及第i-1停在了哪一行,很容易进行状态
#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 2e6 + 10;
char a[N], b[N];
int f[N][2];
int n;

int main(){
    int T; cin >> T;
    while(T--){
        scanf("%d", &n);
        scanf("%s", a + 1);
        scanf("%s", b + 1);
        int l = 2e9, r = 0;
        for(int i = 1; i <=n; i ++){
            if(a[i] == '*' || b[i] == '*') l = min(l, i), r = max(r, i);
        }
        // 初始化
        if(a[l] == '*' && b[l] == '*') f[l][0] = 1, f[l][1] = 1;
        else if(a[l] == '*') f[l][0] = 0, f[l][1] = 1;
        else if(b[l] == '*') f[l][0] = 1, f[l][1] = 0;

        // 状态转移
        for(int i = l + 1; i <= r; i ++){
            if(a[i] == '*' && b[i] == '*'){
                f[i][0] = min(f[i - 1][0] + 2, f[i - 1][1] + 2);
                f[i][1] = min(f[i - 1][0] + 2, f[i - 1][1] + 2);
            }
            else if(a[i] == '*' && b[i] != '*'){
                f[i][0] = min(f[i - 1][0] + 1, f[i - 1][1] + 2);
                f[i][1] = min(f[i - 1][0] + 2, f[i - 1][1] + 2);
            }
            else if(a[i] != '*' && b[i] == '*'){
                f[i][0] = min(f[i - 1][0] + 2, f[i - 1][1] + 2);
                f[i][1] = min(f[i - 1][0] + 2, f[i - 1][1] + 1);
            }
            else{
                f[i][0] = min(f[i - 1][0] + 1, f[i - 1][1] + 2);
                f[i][1] = min(f[i - 1][1] + 1, f[i - 1][0] + 2);
            }
        }
        cout << min(f[r][0], f[r][1]) << endl;
    }
    return 0;
}
posted @ 2022-05-14 10:49  牛佳文  阅读(53)  评论(0编辑  收藏  举报