[题解]AT_abc325_g [ABC325G] offence

思路

看到消除区间,并且 \(|S| \leq 300\) 果断选择区间 DP。

定义 \(dp_{i,j}\) 表示操作 \(i \sim j\) 区间能剩下最少数量。

首先枚举 \(i,j\),然后枚举一个分解点 \(k\),那么显然有 \(dp_{i,j} = \min_{i \leq k < j}\{dp_{i,k} + dp_{k + 1,j}\}\)

如果 \(s_i\)o,需要单独考虑一下。

依旧在 \(k \in (i,j]\) 寻找 \(s_k\)f\(k\),如果 \(dp_{i + 1,k - 1}\) 不为 \(0\),表明 \((i + 1) \sim (k - 1)\) 不能完全操作掉,因此无法使得 \(i,k\) 挨在一起,形成 of

所以当我们找到满足 \(dp_{i + 1,k - 1} = 0\)\(k\) 时,\(i \sim k\) 中的所有元素都能被消除,并且可以在 \(k\) 之后顺手消除 \(K\) 个,所以直接将 \(dp_{i,j}\) 设为 \(\min(dp_{i,j},\max(dp_{k + 1,j} - K,0))\) 即可。

Code

#include <bits/stdc++.h>  
#define re register  
  
using namespace std;  
  
const int N = 310;  
int n,m;  
int dp[N][N];  
string s;  
  
int main(){  
    ios::sync_with_stdio(0);  
    cin.tie(0);  
    cout.tie(0);  
    cin >> s >> m;  
    n = s.size();  
    s = ' ' + s;  
    for (re int i = 1;i <= n;i++){  
        for (re int j = i;j <= n;j++) dp[i][j] = j - i + 1;  
    }  
    for (re int l = 2;l <= n;l++){  
        for (re int i = 1;i + l - 1 <= n;i++){  
            int j = i + l - 1;  
            if (l == 2){  
                if (s[i] == 'o' && s[j] == 'f') dp[i][j] = 0;  
            }  
            else{  
                for (re int k = i;k < j;k++) dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j]);  
                if (s[i] == 'o'){  
                    for (re int k = i + 1;k <= j;k++){  
                        if (s[k] == 'f' && !dp[i + 1][k - 1]) dp[i][j] = min(dp[i][j],max(dp[k + 1][j] - m,0));  
                    }  
                }  
            }  
        }  
    }  
    cout << dp[1][n];  
    return 0;  
}  
posted @ 2024-06-23 00:26  WBIKPS  阅读(29)  评论(0)    收藏  举报