UVA 10617 Again Palindrome

大意不再赘述。

思路:有了上一道回文串的题为基础,这一道题便很好思考了。由于只有删除操作,比较方便,所以我们用d[i][j]表示区间i~j内回文串的个数,初始化d[i][i] = 1,因为单个字符一定是回文串,而我们开始时,则需要从两个端点开始推。

基于删除操作的转移方程:

d[i][j] = d[i+1][j] + d[i][j-1] + 1;(str[i] == str[j]) ①

d[i][j] = d[i+1][j] + d[i][j-1] + d[i+1][j-1];(str[i] != str[j]) ②

①很好理解,一直递推下去,然后由于中间的子串可能为空,则在删除的操作上+1。②要减去一段重复的这一点我倒是没想出来,后来把图画出来发现果真如此,重复的就是一个串的子串,d[i+1][j-1]。

还有这题超INT,需用long long .

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;

const int MAXN = 1010;

typedef long long LL;

char str[65];
LL d[70][70];
bool vis[70][70];

void init()
{
	memset(vis, 0, sizeof(vis));
}

LL dp(int i, int j)
{
	LL &ans = d[i][j];
	if(vis[i][j]) return ans;
	vis[i][j] = 1;
	if(i > j) ans = 0;
	else if(i == j) ans = 1;
	else if(str[i] == str[j])
	{
		ans = dp(i+1, j) + dp(i, j-1) + 1;
	}
	else
	{
		ans = dp(i+1, j) + dp(i, j-1) - dp(i+1, j-1);
	}
	return ans;
}

void read_case()
{
	init();
	scanf("%s", str+1);
}

void solve()
{
	read_case();
	int n = strlen(str+1);
	LL ans = dp(1, n);
	printf("%lld\n", ans);
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		solve();
	}
	return 0;
}


你可能感兴趣的:(UVA 10617 Again Palindrome)