acm-(区间dp、回文串、子序列)ICPC SG Preliminary Contest 2018 C - Making Palindromes

题面
kattis传送门
vj传送门
对于 s s s串而言,考虑设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示所有长度为 l e n = j − i + 1 + k len=j-i+1+k len=ji+1+k的包含 s [ i ∼ j ] s[i\sim j] s[ij]的子串为子序列的回文串的个数,其也等价于在 s [ i ∼ j ] s[i\sim j] s[ij]的基础上再添加 k k k个任意字符串使得字符串成为一个回文串的方案数,注意保证这些回文串两两不同,那么 d p [ 1 ] [ n ] [ n ] dp[1][n][n] dp[1][n][n]即为答案。假设串 s [ i ∼ j ] = X . . . Y , X ≠ Y s[i\sim j]=X...Y,X\ne Y s[ij]=X...Y,X=Y,那么考虑这些符合条件的回文串的特点,首先该回文串的两端的字符可以是 26 26 26个字母中的任意一个,不过有两个字母比较特殊,那就是 X X X Y Y Y,先考虑字母 A , A ≠ X , A ≠ Y A,A\ne X,A\ne Y A,A=X,A=Y,我们把 A A A字母填充到这个长为 l e n len len的回文串两端。如下图所示:
图一
由于我们要求 s [ i ∼ j ] s[i\sim j] s[ij]必须被包含在上图所示的回文串中,而目前位置1和位置 l e n len len都被一个既不是 X X X又不是 Y Y Y的字母所占据,因此我们只能要求回文串的 2 ∼ l e n − 1 2\sim len-1 2len1位置中包含 s [ i ∼ j ] s[i\sim j] s[ij],首先可以肯定上图回文串的 2 ∼ l e n − 1 2\sim len-1 2len1部分肯定也是一个回文串,于是我们要求出一个长度为 l e n − 2 len-2 len2的包含 s [ i ∼ j ] s[i\sim j] s[ij]作为子序列的回文串的个数,它等于 d p [ i ] [ j ] [ k − 2 ] dp[i][j][k-2] dp[i][j][k2]

不过当 A = X A=X A=X的时候,如下图所示:
图二
由于是左边的 X X X已经与 s [ i ] s[i] s[i]相同,因此我们可以发现只要求上图回文串的 2 ∼ l e n − 1 2\sim len-1 2len1位置包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]作为子序列即可,注意这个条件是个充要条件。如果你要问为什么不可以包含 s [ i ∼ j ] s[i\sim j] s[ij]作为子序列,其实只要稍加思考可以发现 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]本身就是 s [ i ∼ j ] s[i\sim j] s[ij]的子序列,我们求出包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]作为子序列的回文串,自然也会包含所有可能的以 s [ i ∼ j ] s[i\sim j] s[ij]作为子序列的回文串。不过你不能让条件变为包含 s [ i + 2 ∼ j ] s[i+2\sim j] s[i+2j]作为子序列,这样显然是不能通过一个 X X X转移到 s [ i ∼ j ] s[i\sim j] s[ij]的。

那么回文串 2 ∼ l e n − 1 2\sim len-1 2len1包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]作为子序列的方案数其实就是 d p [ i + 1 ] [ j ] [ k − 1 ] dp[i+1][j][k-1] dp[i+1][j][k1]

如果将 X X X换成 Y Y Y也是同样地道理。

于是我们可以将这些状态加起来,得到 d p [ i ] [ j ] [ k ] = d p [ i + 1 ] [ j ] [ k − 1 ] + d p [ i ] [ j − 1 ] [ k − 1 ] + 24 d p [ i ] [ j ] [ k − 2 ] dp[i][j][k]=dp[i+1][j][k-1]+dp[i][j-1][k-1]+24dp[i][j][k-2] dp[i][j][k]=dp[i+1][j][k1]+dp[i][j1][k1]+24dp[i][j][k2]

对于 s [ i ∼ j ] = X . . . X s[i\sim j]=X...X s[ij]=X...X的情况其实也就不难推了,跟上面相同,分类讨论一下即可,这里只有两种情况,要么最两端字母不为 X X X,有25种情况,要么最两端字母为 X X X,这种情况单独考虑,于是总方程为 d p [ i ] [ j ] [ k ] = d p [ i + 1 ] [ j − 1 ] [ k ] + 25 d p [ i ] [ j ] [ k − 2 ] dp[i][j][k]=dp[i+1][j-1][k]+25dp[i][j][k-2] dp[i][j][k]=dp[i+1][j1][k]+25dp[i][j][k2]

不过还有一些边界条件需要处理。
k < 0 k<0 k<0时,这时候意味着没办法添加字符,这时候方案数一定为0。

i > j i>j i>j时,这时候我们只需要添加 k k k个任意字符就是所有的方案数,由于是回文串,只需要决定前 ⌈ k 2 ⌉ \lceil \frac k2\rceil 2k个字符就可以决定整个回文串,因此方案数为 2 ⌈ k 2 ⌉ 2^{\lceil \frac k2\rceil} 22k

i = j i=j i=j时,这时候我们可不能当成 s [ i ∼ j ] = X . . . X s[i\sim j]=X...X s[ij]=X...X的这种情况处理,因为在这种情况下你在回文串两端添加一个 X X X就能成功契合 s [ i ∼ j ] s[i\sim j] s[ij]两端的 X X X,但 i = j i=j i=j时其实只有一个 X X X,所以需要特判。这里直接容斥即可,由于回文串长度为 k + 1 k+1 k+1,如果无限制的话总方案数为 2 6 ⌈ k + 1 2 ⌉ 26^{\lceil \frac {k+1}2\rceil} 262k+1,然后除去其中不包含 s [ i ] s[i] s[i]的回文串,这些回文串有 2 5 ⌈ k + 1 2 ⌉ 25^{\lceil \frac {k+1}2\rceil} 252k+1个,剩下的就是包含至少一个 s [ i ] s[i] s[i]的回文串。

这里给出一份参考代码:

int dp[maxn][maxn][maxn];
char s[maxn];

inline int dfs(int i,int j,int k){
	if(k<0)return 0;
	if(~dp[i][j][k])return dp[i][j][k];
	register int &ans=dp[i][j][k];
	if(i>j)ans=qpow(26,k+1>>1,mod);
	else if(i==j)ans=sub(qpow(26,k+2>>1,mod),qpow(25,k+2>>1,mod));
	else if(s[i]==s[j])ans=sum(dfs(i+1,j-1,k),25ll*dfs(i,j,k-2)%mod);
	else ans=sum(sum(dfs(i+1,j,k-1),dfs(i,j-1,k-1)),24ll*dfs(i,j,k-2)%mod);
	return ans;
}
int main(){
	int n=rd();
	if(!n)return wrn(1),0;
	rds(s+1);
	FOR(i,0,n+2)
	FOR(j,0,n+2)
	FOR(k,0,n+1)dp[i][j][k]=-1;
	wrn(dfs(1,n,n));
} 
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页