[编程之美]资格赛 B Palindrome

14 篇文章 0 订阅
3 篇文章 0 订阅

既然这个是资格赛,  时间也比较充裕, 我就讲解一下我做题的过程

Time Limit: 2000ms
Case Time Limit: 1000ms
Memory Limit: 256MB

Description

Given a string, calculate the number of subsequences that are palindrome. A palindrome is a sequence of characters that reads the same backward or forward. For example, in the string “aba”, there are 7 subsequences "a", "b", "a", "ab", "aa", "ba", "aba". Only "a", "b", "a", "aa", "aba" are palindrome. Two subsequences that contain characters from different positions are considered different.

Input

The first line of input contains a single integer T specifying the number of test cases.  In each test case, there is only one line containing a string.

Output

For each test case, output a line containing "Case #X: Y", where X is the test case number starting from 1, followed by one integer Y indicating the number of palindrome subsequences. Output the answer modulo 100007.

Limits

1 ≤ T ≤ 30

Small

Length of string ≤ 25

Large

Length of string ≤ 1000

Sample Input
5
aba
abcbaddabcba
12111112351121
ccccccc
fdadfa
Sample Output
Case #1: 5
Case #2: 277
Case #3: 1333
Case #4: 127
Case #5: 17

我最先想到的就是枚举法了,  把所有的子列都列举出来, 一一判断它们是不是回文串

枚举的方法即使用二项式, 通过二进制数判断哪些字符应当出现在子列中:

#include <iostream>
#include <string>
using namespace std;

int main(void){
	int T,count=0;
	cin >> T;

	int result[30];
	for (int mem = 0; mem < 30; mem++)
	{

		result[mem] = 0;
	}
	while (count<T)
	{
		char a[1000];
		cin >> a;
		int g = 0;
		while (a[g]!='\0')
		{
			g++;
		}
		int size = g;
		for (int i = 1; i < 1<<size; i++)
		{
			//string sub;
			char* sub;
			sub = (char*)malloc(size*sizeof(char));
			int appear = 0;
			for (int j = 0; j < size; j++)
			{
				
				if ((1 << j)&i){
					sub[appear++] = a[j];
				}
			}
			bool ok = true;
			int ii = 0;
			int jj = appear;
			for (int k = 0; ii <= (int)(jj/2); ii++)
			{
				if (sub[ii]!=sub[jj+k-ii-1])
				{
					ok = false;
				}
			}
			if (ok)
			{
				result[count]++;
			}
		}
		count++; 
	}
	count = 1;
	while (count<=T)
	{
		std::cout <<"Case #"<<count<<": "<< result[count-1] << endl;
		count++;
	}
	return 0;
}
带入sample 是测试成功的, 但是提交之后显示time limited exceeded

想想枚举法, 最大字符串有 长度为1000, 那我要枚举2^1000次, 早就溢出了,  

所以思考更高效的算法

将相同的字符两两配对, 组成一组, 利用递归的思想, 思考这两字符之间有几个其他的字符对

#include <iostream>
#include <string>
#include <vector>

using namespace std;

char a[1000];

int findPalindrome(int floor, int ceil){
	int result = 0;
	for (int i = floor; i <= ceil; i++)
	{
		for (int j = i; j <= ceil; j++)
		{
			if (a[i]==a[j])
			{
				if (i == j || i + 1 == j)
				{
					result += 1;
				}
				else
				{
					result++;
					result += findPalindrome(i+1, j-1);
				}
			}
		}
	}
	return result;
}

int main(void){
	int T, count = 0;
	cin >> T;
	
	int result[30];
	for (int mem = 0; mem < 30; mem++)
	{
		result[mem] = 0;
	}
	while (count<T)
	{
		for (int i = 0; i < 1000; i++)
		{
			a[i] = '\0';
		}
		cin >> a;
		int g = 0;
		while (a[g] != '\0')
		{
			g++;
		}
		result[count] = findPalindrome(0, g-1);
		count++;
	}
	count = 1;
	while (count <= T)
	{
		std::cout << "Case #" << count << ": " << result[count - 1] << endl;
		count++;
	}
	return 0;
}
Accept


欢迎大家与我交流.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值