Codeforces Round #427 (Div. 2) D.Palindromic characteristics【DP、後綴和】

D. Palindromic characteristics

題意:

k-迴文的定義:

1.它的左半部分等於右半部分,即本身是1-迴文。

2.它的左半部分和右半部分都是(k-1)-迴文,奇數長度不考慮正中間。

給你一串長度爲n的字符串,讓你統計其所有子串中,是1-迴文到n-迴文的個數,並輸出。

思路:

1.暴力枚舉所有子串,計算它們的最高迴文等級。

2.dp[i][j]表示從第i位到第j位的最高迴文等級爲dp[i][j]

3.預處理長度小於等於2的子串。

4.先判斷計算的子串是不是迴文串,如果不是迴文串則dp[i][j] = 0。如果是迴文串,即滿足題意中的1。

5.計算的子串長度爲偶數時,dp[l][r] = dp[l][mid] + 1

6.計算的子串長度爲奇數時,dp[l][r] = dp[l][mid-1] + 1

7.統計一下後綴和就是結果,因爲k迴文一定是k-1迴文。

代碼:

#include <bits/stdc++.h>
using namespace std;
int dp[5050][5050]; //表示從i到j的迴文等級爲dp[i][j]
int ans[5050];
int main() {
    string s;
    cin >> s;
    int n = s.size();
    memset(ans, 0, sizeof(ans));
    memset(dp, 0, sizeof(dp));
    //len=1時,迴文等級等於1
    for(int i = 0; i < n; ++ i)
        dp[i][i] = 1;
    //len=2時,如果兩個相等,那回文等級等於2,不然就不是迴文串
    for(int i = 0; i < n - 1; ++ i)
        dp[i][i+1] = (s[i] == s[i+1] ? 2 : 0);
    //從len=3開始,n2遍歷求dp[i][j],長度大的可以由長度小的遞推而來,所以len從小到大遍歷
    for(int len = 3; len <= n; ++ len) {
        for(int l = 0; l <= n - len; ++ l) {
            int r = l + len - 1;
            //因爲要求左字符串等於右字符串,所以也就是說整個字符串必須是迴文串
            if(s[l] != s[r] || dp[l + 1][r - 1] == 0) {
                dp[l][r] = 0;
                continue;
            }

            //自己拿個紙畫下就知道邊界怎麼寫
            //由於已經知道字符串是迴文串,所以它的結果就等於左邊/右邊等級+1
            //如果左邊不是迴文串,那麼0+1就是1,也就是整個字符串迴文等級爲1
            int mid = l + r >> 1;
            if(len % 2 == 0) {
                dp[l][r] = dp[l][mid] + 1;
            } else {
                dp[l][r] = dp[l][mid - 1] + 1;
            }
        }
    }
    //統計下最大等級爲i的個數ans[i]
    for(int len = 1; len <= n; ++ len) {
        for(int l = 0; l <= n - len; ++ l) {
            ans[dp[l][l + len - 1]]++;
        }
    }
    //求後綴和。因爲k迴文一定是k-1迴文
    for(int i = n - 1; i >= 1; -- i) {
        ans[i] += ans[i + 1];
    }
    for(int i = 1; i <= n; ++ i) {
        if(i > 1) putchar(' ');
        printf("%d", ans[i]);
    }
    putchar('\n');
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章