题面
题意
给出一个字符串,可以去掉若干个字符,使它变为回文串的方法有几种.
方法
可以发现,任何一种操作都可以通过不断进行以下三种得到:
1.去掉第一个.dp[i][j]+=dp[i+1][j]
2.去掉最后一个.dp[i][j]+=dp[i][j-1]
3.两边都不去掉(在两端相同的情况下)dp[i][j]+=dp[i+1][j-1]
注意,一二操作同时进行时有重叠部分(dp[i+1][j-1]),相加时要减去.
且再进行三操作时+1(仅有i,j两点组成的字符串)
故最终的方法为:
#define ll long long
ll dfs(ll u,ll v)
{
if(v<=u)
{
if(u==v) return 1;
return 0;
}
if(dp[u][v]!=-1) return dp[u][v];
ll res=0;
res+=dfs(u+1,v)+dfs(u,v-1);
if(ch[u]==ch[v]) res++;
else res-=dfs(u+1,v-1);
dp[u][v]=res;
return res;
}
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,TT,dp[70][70];
char ch[70];
ll dfs(ll u,ll v)
{
if(v<=u)
{
if(u==v) return 1;
return 0;
}
if(dp[u][v]!=-1) return dp[u][v];
ll res=0;
res+=dfs(u+1,v)+dfs(u,v-1);
if(ch[u]==ch[v]) res++;
else res-=dfs(u+1,v-1);
dp[u][v]=res;
return res;
}
int main()
{
ll i,j;
cin>>T;
TT=T;
while(T--)
{
scanf("%s",ch+1);
memset(dp,-1,sizeof(dp));
printf("Case %lld: %lld\n",TT-T,dfs(1,strlen(ch+1)));
}
}