编程之美2015资格赛 题目2 : 回文字符序列 [ 区间dp ]
题目2 : 回文字符序列
描述
给定字符串,求它的回文子序列个数。回文子序列反转字符顺序后仍然与原序列相同。例如字符串aba中,回文子序列为"a", "a", "aa", "b", "aba",共5个。内容相同位置不同的子序列算不同的子序列。
输入
第一行一个整数T,表示数据组数。之后是T组数据,每组数据为一行字符串。
输出
对于每组数据输出一行,格式为"Case #X: Y",X代表数据编号(从1开始),Y为答案。答案对100007取模。
数据范围
1 ≤ T ≤ 30
小数据
字符串长度 ≤ 25
大数据
字符串长度 ≤ 1000
- 样例输入
-
5
aba
abcbaddabcba
12111112351121
ccccccc
fdadfa - 样例输出
-
Case #1: 5
Case #2: 277
Case #3: 1333
Case #4: 127
Case #5: 17
题解:
思路来自贲神
一开始看错了题,以为是算回文子串(要求连续),结果题目是算回文子序列(不一定要连续)。
故,用区间dp,搞了好久。。。晕死,最后用的是记忆化dp,没想到递推肿么搞。
看了网上的代码后,发现:我的思路还是有偏差。
递推的转移方程应该为:
if (s[i] == s[j])
dp[i][j] = (dp[i + ][j] + dp[i][j - ] + ) % mod;
else
dp[i][j] = (dp[i + ][j] + dp[i][j - ] - dp[i + ][j - ]) % mod;
结果:AC | NA 提交时间:2015-04-17 16:05:34
贴一份其他人ac的代码:
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; const int maxn = ;
char s[maxn];
const int mod = ;
int dp[maxn][maxn]; int solve()
{
memset(dp, , sizeof(dp));
int n = strlen(s); for (int l = ; l <= n; ++l)
{
for (int i = ; i + l < n; ++i)
{
int j = i + l;
if (s[i] == s[j])
dp[i][j] = (dp[i + ][j] + dp[i][j - ] + ) % mod;
else
dp[i][j] = (dp[i + ][j] + dp[i][j - ] - dp[i + ][j - ]) % mod;
}
} return (dp[][n - ]%mod + mod)%mod;
} int main()
{
int T;
cin >> T;
for (int cas = ; cas <= T; ++cas)
{
cin >> s;
printf("Case #%d: %d\n", cas, solve());
}
return ;
}
再贴一发记忆化dp ac的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std; #define mxn 200005
#define LL long long
#define MP make_pair
#define REP(i, a, b) for (int i = a; i <= b; ++i)
#define FOR(i, a, b) for (int i = a; i < b; ++i) #define mod 100007 int dp[][];
char s[]; int F(int l, int r) {
if (dp[l][r] != -) return dp[l][r];
if (l > r) return dp[l][r] = ;
if (l == r) return dp[l][r] = ;
int& ret = dp[l][r];
ret = (F(l + , r) + F(l, r - )) % mod;
if (s[l] == s[r]) ++ret;
else ret -= F(l + , r - );
ret = (ret + mod) % mod;
return ret;
} int main()
{
int cas = , t; scanf("%d", &t);
while (t--) {
memset(dp, -, sizeof(dp));
scanf("%s", s + );
int ans = F(, strlen(s + ));
printf("Case #%d: %d\n", ++cas, ans);
}
return ;
}
我的思路复杂度不好,T了
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <string>
#include <cmath> #define ll long long
int const N = ;
int const M = ;
int const INF = 0x7fffffff;
int const mod = ; using namespace std; int T,cnt;
int dp[N][N];
char s[N];
int l;
int ans; void ini()
{
scanf("%s",s+);
l=strlen(s+);
memset(dp,-,sizeof(dp));
} int dfs(int st,int en)
{
if(dp[st][en]!=-) return dp[st][en];
if(st>en){
return dp[st][en]=;
}
if(st==en){
return dp[st][en]=;
}
dp[st][en]=dfs(st,en-)+;
// printf(" st=%d en=%d dp=%d\n",st,en,dp[st][en]); int i;
for(i=st;i<en;i++){
if(s[i]==s[en])
dp[st][en]=(dp[st][en]+dfs(i+,en-)+)%mod;
}
return dp[st][en];
} void solve()
{
ans=dfs(,l);
} void out()
{
/*
int i,j;
for(i=1;i<=l;i++){
for(j=i;j<=l;j++){
printf(" i=%d j=%d dp=%d\n",i,j,dp[i][j]);
}
}*/
printf("Case #%d: %d\n",cnt,ans);
} int main()
{
//freopen("data.in","r",stdin);
scanf("%d",&T);
for(cnt=;cnt<=T;cnt++)
// while(T--)
//while(scanf("%d%d",&n,&m)!=EOF)
{
ini();
solve();
out();
} return ;
}
编程之美2015资格赛 题目2 : 回文字符序列 [ 区间dp ]的更多相关文章
- 编程之美2015 资格赛 hihocoder 题目2: 回文字符序列
思路:暴力搜,用BFS的方式,生成每一种可能,再对每一种可能进行判断是否回文,进行统计.严重超时!计算一个25个字符的,大概要20多秒! #include <iostream> #incl ...
- HDU 4745 Two Rabbits ★(最长回文子序列:区间DP)
题意 在一个圆环串中找一个最长的子序列,并且这个子序列是轴对称的. 思路 从对称轴上一点出发,向两个方向运动可以正好满足题意,并且可以证明如果抽选择的子环不是对称的话,其一定不是最长的. 倍长原序列, ...
- 合并回文子串(区间dp)
链接:https://ac.nowcoder.com/acm/problem/13230来源:牛客网 题目描述 输入两个字符串A和B,合并成一个串C,属于A和B的字符在C中顺序保持不变.如" ...
- hdu4632 Palindrome subsequence 回文子序列个数 区间dp
Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65535 K (Java/ ...
- 便宜的回文串(区间DP)
题目链接:便宜的回文串 这道题刚开始其实还是没有思路的.没办法,只能看题解了... 其实我们在思考问题时,考虑到一段串增或减时会改变它的长度,所以转移时会麻烦... 但其实不用考虑那么多的问题,我们只 ...
- [HIHO1323]回文字符串(区间dp)
题目链接:http://hihocoder.com/problemset/problem/1323 思路:区间dp,按照区间长度枚举所有区间和区间的起始位置.这时也可获取到区间的末位,比对这两个字符是 ...
- hihocoder1323 回文字符串(区间dp)
https://hihocoder.com/problemset/problem/1323 刚开始真没看出来这是一道dp题.. dp[i][j]表示i~j段修改成回文串所需的最少操作次数.然后根据s[ ...
- hihoCoser(#1149 : 回文字符序列)
时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为"a& ...
- 【HIHOCODER 1323】回文字符串(区间DP)
描述 给定一个字符串 S ,最少需要几次增删改操作可以把 S 变成一个回文字符串? 一次操作可以在任意位置插入一个字符,或者删除任意一个字符,或者把任意一个字符修改成任意其他字符. 输入 字符串 S. ...
随机推荐
- SQL Server 2012使用OFFSET/FETCH NEXT分页及性能测试
最近在网上看到不少文章介绍使用SQL Server 2012的新特性:OFFSET/FETCH NEXT 实现分页.多数文章都是引用或者翻译的这一篇<SQL Server 2012 - Serv ...
- 浅析 innerHTML 性能优化的原理
浅析 innerHTML 性能优化的原理 博客分类: web前端 IEAndroidwebkit浏览器UI 昨天看了 lveyo老兄的"innerHTML的性能问题" 一文 ht ...
- 回顾Spring MVC_01_概述_入门案例
SpringMVC: SpringMVC是Spring为展现层提供的基于MVC设计的优秀的Web框架,是目前最主流的MVC框架之一 SpringMVC通过注解,让POJO成为处理请求的控制器,而无须实 ...
- Python3简明教程(五)—— 流程控制之循环
有些时候我们需要多次执行相同的任务,我们使用一个计数器来检查代码需要执行的次数.这个技术被称为循环. while循环 while语句的语法如下: while condition: statement1 ...
- swift学习——枚举
swift枚举 1. 枚举基本语法 enum Method { case Add case Sub case Mul case Div } 也可以使用一种更简单的写法 enum Method1{ ca ...
- 20道必须掌握的C++面试题
20道必须掌握的C++面试题 在面试C++方面的工作时,经常会遇到各种面试题,这对应聘人员的知识掌握能力要求较高.本文将为大家带来的就是20道必须掌握的C++面试题,不要错过哦! 问1:请用简单的语言 ...
- QT+信号有参数与无参数的实现+QT4和QT5在信号和槽使用上的区别
在QT5中,信号有参数和无参数 #ifndef SUBWIDGET_H #define SUBWIDGET_H #include <QWidget> #include <QPushB ...
- django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module
pip3 install mysqlclient try again python manage.py makemigrations python manage.py migrate
- vue在传值的时候经常遇到的问题
在我用vue编写程序的时候,在传值的时候,经常会遇到些问题,像今天遇到了两个问题,在用父传子的方法去传值,当父组件中的要传的数据是for循环出来的或者是列表的时候,你想每次运行的事件,都去传某一行,或 ...
- js div大小随意伸缩
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...