CF1385D a-Good String

原题链接:Problem - 1385D - Codeforces

这是一道好题,本质上是使用动态规划(分治)去处理每个区间。DP 本身是很简单的,难点在于范围处理和时间的估计。本身是没什么难度的,只是范围有些复杂,容易算错,这时候就建议列表去发现规律了。

列表是一种快速,不易错的数据统筹方式,可以方便对范围进行控制找寻。多设点 \(len\) 变量吧。

就不多说了,是一道练习区间范围基本功的好题,练习代码实现能力。自己试试吧。

预处理:

/*
列表,定点,定长度,找点的魅力
*/

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>


using namespace std;

const int N = 50, M = 140010 * 2;

int n, m;
int f[N][M], sum[N][M];
string s;

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        cin >> n >> s;
        m = log2(n);

        for (int j = 1; j <= m + 1; j ++ )
        {
            char x = 'a' + j - 1;
            for (int i = 1; i <= n; i ++ )
            {
                if (x != s[i - 1]) sum[j][i] = 1;
                else sum[j][i] = 0;
                sum[j][i] += sum[j][i - 1];
            }
        }

        for (int i = 1; i <= n; i ++ ) f[m + 1][i] = sum[m + 1][i] - sum[m + 1][i - 1];
        
        for (int i = m; i >= 0; i -- )
            for (int j = 1; j <= 1 << i - 1; j ++ )
                f[i][j] = min(f[i + 1][j * 2 - 1] - sum[i][(2 * j - 1) * (1 << m - i)] + sum[i][(2 * j) * (1 << m - i) ], f[i + 1][j * 2] - sum[i][(2 * j - 2) * (1 << m - i)] + sum[i][(2 * j - 1) * (1 << m - i)]);
        
        cout << f[1][1] << endl;
    }
    
    return 0;
}

在线处理(实际上最后算出来还是 \(n\log n\) 的计算数量 ),而非 \(\operatorname O(n^2\log n)\)

/*
定点,定长度
*/

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>


using namespace std;

const int N = 50, M = 140010 * 2;

int n, m;
int f[N][M];
string s;

int get(int x, int l, int r) // 在线计算区间内需要转换的点的数量
{
    int cnt = 0;
    for (int i = l - 1; i < r; i ++ )
    {
        char a = 'a' + x - 1;
        if (a != s[i]) cnt ++ ;
    }
    return cnt;
}

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        cin >> n >> s;
        m = log2(n);
        // m ++ ;

        for (int i = 1; i <= n; i ++ ) f[m + 1][i] = get(m + 1, i, i);
        for (int i = m; i >= 0; i -- )
            for (int j = 1; j <= 1 << i - 1; j ++ )
                f[i][j] = min(f[i + 1][j * 2 - 1] + get(i, (2 * j - 1) * (1 << m - i) + 1, (2 * j) * (1 << m - i)), f[i + 1][j * 2] + get(i, (2 * j - 2) * (1 << m - i) + 1, (2 * j - 1) * (1 << m - i)));
        
        cout << f[1][1] << endl;
    }
    
    return 0;
}
posted @ 2025-09-26 21:29  blind5883  阅读(6)  评论(0)    收藏  举报