编程之美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. ...
随机推荐
- IO 优化
转自 BlackJack_ #define fastcall __attribute__((optimize("-O3"))) #define IL __inline__ __at ...
- 洛谷P2762 太空飞行计划问题(最大权闭合图)
题意 有$m$个实验,$n$中器材,每个实验需要使用一些器材 每个实验有收入,每个器材有花费 最大化收入 - 花费 Sol 最大权闭合图的经典应用 从$S$向每个实验连流量为该实验收入的边 从每个器材 ...
- vue-cli下配置项目访问ip和服务器ip
一.配置项目访问ip,让本次代码支持localhost以外的ip地址访问模式:修改里的host配置,代码如下. 修改完记得 "npm run dev"重启服务. 二.在本地架设服务 ...
- 如何处理Docker的错误消息request canceled:Docker代理问题
在本地安装Kubernetes时,遇到错误消息: request canceled while waiting for connection(Client.Timeout exceeded while ...
- centos7 取消Ctrl+Alt+Del重启功能
转载:http://www.cnblogs.com/huangjc/p/4536620.html Linux默认允许任何人按下Ctrl+Alt+Del来重启系统.但是在生产环境中,应该停用按下Ctrl ...
- MFC实现类似spy++dm取句柄功能
处理WM_MOUSEMOVE消息 HANDLE_MSG( hwnd , WM_MOUSEMOVE, OnMouseMove ) 在OnMouseMove中, 设置SetCaputre() 移动鼠标到目 ...
- The MySQL server is running with the –secure-file-priv
show variables like '%secure%'; 将文件导出路径更改为查询到的secure-file-priv路径下 select * from table where column = ...
- SQL Server 2008 阻止保存要求重新创建表的更改
取消[阻止保存要求重新创建表的更改]复选框
- Android典型界面设计-访网易新闻实现双导航tab切换
一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客 ...
- Openjudge-4151-电影节
这个题是一道贪心的题目,我们要想看的电影数目最多,我们肯定每次都要选最早结束的电影,这样我们才能去看下一部电影. 它本身最早结束,如果同时开始,那肯定是它的放映时间比较短,如果它后开始,先结束,那它的 ...