NOIP2018提高组金牌训练营——字符串专题

NOIP2018提高组金牌训练营——字符串专题

1154 回文串划分

有一个字符串S,求S最少可以被划分为多少个回文串。
例如:abbaabaa,有多种划分方式。
 
a|bb|aabaa - 3 个回文串
a|bb|a|aba|a - 5 个回文串
a|b|b|a|a|b|a|a - 8 个回文串
 
其中第1种划分方式的划分数量最少。
Input
输入字符串S(S的长度<= 5000)。
Output
输出最少的划分数量。
Input示例
abbaabaa
Output示例
3


复习了一波划分型dp
可以直接暴力处理出i到j是否是回文串,dp即可
但是这个暴力理论上是n^3的,但大多数情况下对于i到j两端不同很快就退出了,
所以还是可以过的,最大的数据达到0.5s
#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 5000 + 10;
int a[MAXN][MAXN], dp[MAXN];
char s[MAXN];

bool judge(int i, int j)
{
    while(i < j)
    {
        if(s[i] != s[j]) return false;
        i++; j--;
    }
    return true;
}

int main()
{
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    
    _for(i, 1, n)
        _for(j, i, n)
            a[i][j] = judge(i, j);
            
    memset(dp, 0x3f, sizeof(dp));
    dp[0] = 0;
    _for(j, 1, n)
    {
        _for(i, 1, j)
            if(a[i][j])
              dp[j] = min(dp[j], dp[i-1] + 1);
    }

    printf("%d\n", dp[n]);
    return 0;
}

但是讲解里面貌似有更快的方法。

一种是dp

如果s[i] == s[j], 那么S[i……j]是否是回文串取决于S[i+1……j-1]是否是回文串

可以用这个思路dp

但是实际上的时间却比暴力要慢(0.7S)

应该是循环内判断比较多,以及暴力大多数很快就判断出不是回文串的缘故

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 5000 + 10;
int a[MAXN][MAXN], dp[MAXN];
char s[MAXN];

int main()
{
    scanf("%s", s + 1);
    int n = strlen(s + 1);
            
    _for(d, 1, n)
        _for(l, 1, n)
        {
            int r = l + d - 1;
            if(r > n) break;
            if(s[l] == s[r])
            {
                if(l + 1 >= r - 1) a[l][r] = 1;
                else a[l][r] = a[l+1][r-1];
            }
        }
        
    memset(dp, 0x3f, sizeof(dp));
    dp[0] = 0;
    _for(j, 1, n)
    {
        _for(i, 1, j)
            if(a[i][j])
              dp[j] = min(dp[j], dp[i-1] + 1);
    }

    printf("%d\n", dp[n]);
    return 0;
}
第二种是用Manacher
代码量会多很多,就不写了
所以还是暴力出奇迹



猜你喜欢

转载自www.cnblogs.com/sugewud/p/9838981.html