[编程之美]资格赛 B Palindrome

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

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

本人才疏学浅, 欢迎大家与我交流.

时间: 2024-10-07 22:40:29

[编程之美]资格赛 B Palindrome的相关文章

编程之美资格赛 大神与三位小伙伴

题目2 : 大神与三位小伙伴 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 L国是一个有着优美景色且物产丰富的国家,很多人都喜欢来这里旅游并且喜欢带走一些纪念品,大神同学也不例外.距离开L国的时间越来越近了,大神同学正在烦恼给她可爱的小伙伴们带什么纪念品好,现在摆在大神同学面前的有三类纪念品A, B, C可以选择,每类纪念品各有N种.其中种类为A_i, B_i, C_i的纪念品价值均为i, 且分别有N+1-i个剩余.现在大神同学希望在三类纪念品中各挑选一件然后赠送给

编程之美-资格赛-回文字符序列

动态规划 #include <iostream> #include <iostream> #include <map> #include <cstring> using namespace std; char a[1005]; const int INF = 100007; int num[1005]; int dp[1005][1005]; int main(){ int n; cin >> n; for(int cases = 1; case

编程之美-资格赛-2月29

简单模拟题 #include <iostream> #include <string> using namespace std; //判断是不是闰年 bool is(int year){ return year % 400 == 0?true: (year % 100 == 0?false:(year % 4 == 0?true:false)); } //判断结束日期是否不包括2月29 #define NO2 (in2Var1 < 3 && !(in2Var1

[2015编程之美] 资格赛C

#1150 : 基站选址 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上. 网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方. 网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离). 在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价. 输入 第一行为一个整数T,表示数据组数. 每组数据第一行为四个整数:N, M

2014编程之美-资格赛-大神与三位小伙伴

题目2 : 大神与三位小伙伴 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 L国是一个有着优美景色且物产丰富的国家,很多人都喜欢来这里旅游并且喜欢带走一些纪念品,大神同学也不例外.距离开L国的时间越来越近了,大神同学正在烦恼给她可爱的小伙伴们带什么纪念品好,现在摆在大神同学面前的有三类纪念品A, B, C可以选择,每类纪念品各有N种.其中种类为A_i, B_i, C_i的纪念品价值均为i, 且分别有N+1-i个剩余.现在大神同学希望在三类纪念品中各挑选一件然后赠送给

编程之美资格赛 第二题 回文字符序列 dp

这是一道dp题,设置dp[i][j]代表的是从i到j之间的有多少个回文子串,dp[i][j] = dp[i][num[1]] +1+ dp[num[1]+1][j - 1]+1......+dp[num[j]][j-1] + 1 ,num[i] 代表的是与i字符相同的上一个字符的位置! 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为"a", &quo

2015微软编程之美资格赛骨牌覆盖(矩阵快速幂)

由于棋盘只有两行,所以如果第i列的骨牌竖着放,那么就转移为第1列到第i-1列骨牌有多少种摆法 如果第一行第i列骨牌横着放,那么第二行第i列也要横着放,那么就转移为了第1列到第i-2列骨牌有多少种方法 dp[i] = dp[i-1] + dp[i-2],但是列数太多了. 这种递推的算式可以用矩阵快速幂来优化 所以时间复杂度瞬间变为O(logn) 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h>

2015编程之美资格赛 回文子序列个数

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为”a”, “a”, “aa”, “b”, “aba”,共5个.内容相同位置不同的子序列算不同的子序列. 输入 第一行一个整数T,表示数据组数.之后是T组数据,每组数据为一行字符串. 输出 对于每组数据输出一行,格式为”Case #X: Y”,X代表数据编号(从1开始),Y为答案.答案对100007取模. 数据范围 

2015编程之美资格赛 A 2月29日

 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: 1. 年份能被4整除但不能被100整除 2. 年份能被400整除 输入 第一行为一个整数T,表示数据组数. 之后每组数据包含两行.每一行格式为"month day, year",表示一个日期.month为{"January", "February&quo