DP-Again Palindrome - UVA - 10617
题意:
给
定
一
个
长
度
为
n
的
字
符
串
,
删
除
一
些
字
符
(
包
括
0
个
)
,
使
得
其
成
为
回
文
串
,
问
共
有
多
少
种
删
法
。
本
质
上
是
问
,
有
多
少
个
子
串
是
回
文
的
。
T
组
测
试
用
例
。
给定一个长度为n的字符串,删除一些字符(包括0个),使得其成为回文串,问共有多少种删法。\\本质上是问,有多少个子串是回文的。\\T组测试用例。
给定一个长度为n的字符串,删除一些字符(包括0个),使得其成为回文串,问共有多少种删法。本质上是问,有多少个子串是回文的。T组测试用例。
Sample Input:
3
BAOBAB
AAAA
ABA
Sample Output:
22
15
5
数据范围:
T
∈
[
1
,
15
]
,
n
∈
[
1
,
60
]
。
T
i
m
e
l
i
m
i
t
:
3000
m
s
T∈[1,15],n∈[1,60]。\\Time\ limit:3000 ms
T∈[1,15],n∈[1,60]。Time limit:3000ms
题解:
设 d p [ i ] [ j ] 表 示 区 间 为 [ i , j ] 的 字 符 串 所 包 含 的 回 文 子 串 的 数 量 。 状 态 转 移 方 程 : ① 、 s [ i ] = s [ j ] 时 , d p [ i ] [ j ] = d p [ i + 1 ] [ j ] + d p [ i ] [ j − 1 ] − d p [ i + 1 ] [ j − 1 ] + ( d p [ i + 1 ] [ j − 1 ] + 1 ) ② 、 s [ i ] ≠ s [ j ] 时 , d p [ i ] [ j ] = d p [ i + 1 ] [ j ] + d p [ i ] [ j − 1 ] − d p [ i + 1 ] [ j − 1 ] 。 理 解 : 对 第 二 种 情 况 , 缩 小 问 题 规 模 , 减 去 的 是 区 间 [ i + 1 , j ] 与 [ i , j − 1 ] 重 叠 部 分 , 类 似 于 容 斥 ; 而 第 一 种 情 况 , 由 于 s [ i ] = s [ j ] , 那 么 这 两 个 字 符 可 以 加 在 [ i + 1 , j − 1 ] 内 的 任 意 回 文 子 串 两 端 构 成 新 的 回 文 串 , 数 量 就 额 外 增 多 了 d p [ i + 1 ] [ j − 1 ] 个 , 再 加 上 [ i , j ] 本 身 算 一 个 回 文 串 , ① 就 在 ② 的 基 础 上 增 加 了 d p [ i + 1 ] [ j − 1 ] + 1 个 。 设dp[i][j]表示区间为[i,j]的字符串所包含的回文子串的数量。\\状态转移方程:\\①、s[i]=s[j]时,dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+(dp[i+1][j-1]+1)\\②、s[i]≠s[j]时,dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]。\\ \ \\理解:对第二种情况,缩小问题规模,减去的是区间[i+1,j]与[i,j-1]重叠部分,类似于容斥;\\而第一种情况,由于s[i]=s[j],那么这两个字符可以加在[i+1,j-1]内的任意回文子串两端构成新的回文串,\\数量就额外增多了dp[i+1][j-1]个,再加上[i,j]本身算一个回文串,①就在②的基础上增加了dp[i+1][j-1]+1个。 设dp[i][j]表示区间为[i,j]的字符串所包含的回文子串的数量。状态转移方程:①、s[i]=s[j]时,dp[i][j]=dp[i+1][j]+dp[i][j−1]−dp[i+1][j−1]+(dp[i+1][j−1]+1)②、s[i]=s[j]时,dp[i][j]=dp[i+1][j]+dp[i][j−1]−dp[i+1][j−1]。 理解:对第二种情况,缩小问题规模,减去的是区间[i+1,j]与[i,j−1]重叠部分,类似于容斥;而第一种情况,由于s[i]=s[j],那么这两个字符可以加在[i+1,j−1]内的任意回文子串两端构成新的回文串,数量就额外增多了dp[i+1][j−1]个,再加上[i,j]本身算一个回文串,①就在②的基础上增加了dp[i+1][j−1]+1个。
具体落实:
① 、 由 于 递 推 是 从 短 推 长 , 所 以 要 先 把 短 的 计 算 好 。 先 预 处 理 长 度 为 1 的 回 文 串 d p [ i ] [ i ] = 1 。 ② 、 按 长 度 处 理 , 长 度 i 从 [ 2 , n ] , 根 据 递 推 关 系 式 , 求 出 每 个 长 度 区 间 下 的 回 文 子 串 个 数 。 ①、由于递推是从短推长,所以要先把短的计算好。先预处理长度为1的回文串dp[i][i]=1。\\②、按长度处理,长度i从[2,n],根据递推关系式,求出每个长度区间下的回文子串个数。 ①、由于递推是从短推长,所以要先把短的计算好。先预处理长度为1的回文串dp[i][i]=1。②、按长度处理,长度i从[2,n],根据递推关系式,求出每个长度区间下的回文子串个数。
注意:
字 符 串 的 长 度 最 大 达 到 60 , 极 端 情 况 下 共 有 约 2 60 种 子 串 , 因 此 d p 数 组 类 型 取 l o n g l o n g 。 字符串的长度最大达到60,极端情况下共有约2^{60}种子串,因此dp数组类型取long\ long。 字符串的长度最大达到60,极端情况下共有约260种子串,因此dp数组类型取long long。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const int N=65;
char s[N];
int T;
ll dp[N][N];
int main ()
{
cin>>T;
while(T--)
{
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;i++) dp[i][i]=1;
for(int i=2;i<=n;i++)
for(int j=1,k=i;k<=n;j++,k++)
{
dp[j][k]=dp[j][k-1]+dp[j+1][k]-dp[j+1][k-1];
if(s[j]==s[k]) dp[j][k]+=dp[j+1][k-1]+1;
}
printf("%lld\n",dp[1][n]);
}
return 0;
}