DP ---------回文配列

長さの文字列sの回文特性|よ| S |のシーケンスであります| k番目の数はK-回文であるSの非空のストリングの総数である整数。
文字列は、それが前方と同じ後方を読み込み場合にのみ、1回文です。
:とする場合にのみ場合、文字列がk-回文(K> 1)である
。その左半分はその右半分に等しいです。
その左右halfsが空(k - 1)である-palindromes。
文字列tの左半分の長さのその接頭辞である⌊|トン| /2⌋、右半分-同じ長さのサフィックス。⌊| T | /2⌋2で割った文字列Tの長さを示し、切り捨て。
それは文字列に表示される各部分が何回としてカウントされることに注意してください。例えば、文字列「AAA」の部分文字列「」3回表示されます。
入力
最初の行は含まれてい文字列s(1≤| S |≤5000)小文字の英文字からなります。
出力
を印刷| S | 整数-文字列sのパリンドローム特徴。

入力
アバの
出力
6 1 0 0
入力
abacabaの
出力
12 4 1 0 0 0 0

最初の例では1-パリンドロームであるストリング«A»、«B»«B»«»«BB»«アバ»、サブ«BBは»2-回文です。ここには3-及び4-回文はありません。

//f[i][j]表示i到j这部分子串的阶数 
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
const int N = 5010;
char s[N];
int f[N][N];
int ans[N];
int main(){
 scanf("%s",s);
 int len = strlen(s);
 for (int i = 0; i < len; i ++){     //枚举每一个长度 
      for (int l = 0; l + i < len; l ++){   //枚举每一个起点 
       if (i == 0)   f[l][l + i] = 1;     // 长度是1的为1阶回文 
       else          if (i == 1)         //长度为2如果左右俩边相等为2阶会文,否则不是回文 
       f[l][l + i] = (s[l] == s[l + 1] ? 2 : 0);
       else     if (s[l] == s[l + i] && f[l + 1][l + i - 1]){ //如果是回文的话 
       f[l][l + i] = 1;
       int mid = (l + l + i) >> 1;
       if (i & 1){             //如果长度为偶数 
         if (f[l][mid] && f[mid + 1][i + l])
         f[l][l + i] = f[l][mid] + 1;     //递归 
    }
   else{
    if (f[l][mid - 1] && f[mid + 1][i + l])
    f[l][l + i] = f[l][mid - 1] + 1;
   }
 }
  }
}
         for (int i = 0; i < len; i ++)
         for (int j = i; j < len; j ++)
            ans[f[i][j]] ++;    //求每一个阶级的个数 
            for (int i = len - 1; i >= 0; i --)
       ans[i] += ans[i + 1];   //阶级大的肯定是阶级小的 
       for (int i = 1; i <= len - 1; i ++)
     printf("%d ",ans[i]);
     printf("%d", ans[len]);
     return 0;
}
公開された106元の記事 ウォン称賛67 ビュー5435

おすすめ

転載: blog.csdn.net/qq_45772483/article/details/104851556