编程之美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. ...
随机推荐
- poj3436 Computer Factory
题意: 电脑公司生产电脑有N个机器,每个机器单位时间产量为Qi. 电脑由P个部件组成,每个机器工作时只能把有某些部件的半成品电脑(或什么都没有的空电脑)变成有另一些部件的半成品电脑或完整电脑(也可能移 ...
- Java基础--java简介
1.Java的起源: Oak --> Java 2.Java的发展 Java1.0 Java2 JavaSE:Java平台标准版 JavaME:微型版 JavaEE:企业版 Sun公司 or ...
- 【人工智能系列】python的Quepy库的学习
第一篇 了解 什么是Quepy quepy是一个Python框架改造自然语言问题在数据库查询语言查询.它可以很容易地定制不同类型的问题,在自然语言和数据库查询.因此,用很少的代码,你可以建立自己的系统 ...
- (转)让Spring自动扫描和管理Bean
http://blog.csdn.net/yerenyuan_pku/article/details/52861403 前面的例子我们都是使用XML的bean定义来配置组件.在一个稍大的项目中,通常会 ...
- [Redis] 基于redis的分布式锁
前言分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁. 可靠性首先,为了确保 ...
- socks5代理原理解析
sock5代理的工作程序是: 1.需要代理方向服务器发出请求信息. 2.代理方应答 3.需要代理方接到应答后发送向代理方发送目的ip和端口 4.代理方与 ...
- SQL Server数据库的除法默认向下取整,要返回小数的解决方法
num1; / 1000.0 num2; * 1.0 num3; num4; 结果:
- 从postgres数据库逆向生成hibernate实体类
最近整理 一个项目,原先的项目是用的oracle,然而新的项目要用postgresql.将oracle数据库导出之后,通过powerdesigner整理,导出postgresql的脚本,然后在post ...
- PHP将数据库的数据转换成json格式
header('content-type:application/json;charset=utf8'); $results = array(); while ($row = mysql_f ...
- 自定义函数导致的sql性能问题
同事说,某某报表跑的很慢,让我调查一下 优化前:该报表整体需要跑4小时以上. sql代码如下 SELECT /*省略多数查询字段*/ REP_FUN_REFCODEVALUE /*自定义函数*/ (P ...