Codeforces Round #427 (Div. 2)

题目链接:http://codeforces.com/contest/835/problem/D

题意:给定一个字符串,定义kth回文是左半部分等于右半部分,并且左半部分和右半部分都是(k-1)th回文。 只要是回文字串都是1th回文。 对于1<=k<=strlen(s),输出kth回文的数量。

思路:预处理出每个子串是否是回文。然后len^2枚举区间,如果s[i][j]是回文的话,继续枚举左半部分s[i][i+(j-i+1)/2-1]是否是回文,是的话再继续枚举左半部分然后顺便统计答案即可。 对于统计贡献,假设s[i][j]连续枚举了x次左半部分都是回文,第x+1次的左半部分不是回文,则说明s[i][j]是xth回文, s[i][j]的左半部分是x-1th回文....相当于把(1~x)th贡献+1,代码里是逆着算贡献即xth回文算到1th中,但是并不影响最后对答案的贡献

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<time.h>
#include<cmath>
#include<set>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = 5000 + 24;
const int INF = 1e9;
const int mod = 1e9 + 7;
char str[MAXN];
LL ans[MAXN];
bool isPalind[MAXN][MAXN];
void Make_Palind(int len){
    for (int i = 0; i < len; i++) {
        int l = i, r = i;
        for (int l = i, r = i; l >= 0 && r < len&&str[l] == str[r]; l--, r++){ //奇长度回文
            isPalind[l][r] = true;
        }
        for (int l = i, r = i + 1; l >= 0 && r < len&&str[l] == str[r]; l--, r++){ //偶长度回文
            isPalind[l][r] = true;
        }
    }
}

int main(){
#ifdef kirito
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    while (~scanf("%s", str)){
        int len = strlen(str);
        memset(ans, 0, sizeof(ans));
        memset(isPalind, false, sizeof(isPalind));
        Make_Palind(len);
        for (int i = 0; i < len; i++){
            for (int j = i; j < len; j++){
                for (int l = i, r = j, k = 1; l >= 0 && r < len && r >= l && isPalind[l][r]; r = l + (r - l + 1) / 2 - 1, k++){
                    ans[k]++;
                }
            }
        }
        for (int i = 1; i <= len; i++){
            printf("%lld%c", ans[i], (i == len ? '
' : ' '));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kirito520/p/7271424.html