题目2 : 回文字符序列
时间限制:2000ms
单点时限:1000ms
内存限制:256MB
描述
给定字符串,求它的回文子序列个数。回文子序列反转字符顺序后仍然与原序列相同。例如字符串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 + 1][j] + dp[i][j - 1] + 1) % mod; else dp[i][j] = (dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]) % mod;
结果:AC | NA 提交时间:2015-04-17 16:05:34
贴一份其他人ac的代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 const int maxn = 1100; 8 char s[maxn]; 9 const int mod = 100007; 10 int dp[maxn][maxn]; 11 12 int solve() 13 { 14 memset(dp, 0, sizeof(dp)); 15 int n = strlen(s); 16 17 for (int l = 0; l <= n; ++l) 18 { 19 for (int i = 0; i + l < n; ++i) 20 { 21 int j = i + l; 22 if (s[i] == s[j]) 23 dp[i][j] = (dp[i + 1][j] + dp[i][j - 1] + 1) % mod; 24 else 25 dp[i][j] = (dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]) % mod; 26 } 27 } 28 29 return (dp[0][n - 1]%mod + mod)%mod; 30 } 31 32 int main() 33 { 34 int T; 35 cin >> T; 36 for (int cas = 1; cas <= T; ++cas) 37 { 38 cin >> s; 39 printf("Case #%d: %d ", cas, solve()); 40 } 41 return 0; 42 }
再贴一发记忆化dp ac的代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #include <algorithm> 6 using namespace std; 7 8 #define mxn 200005 9 #define LL long long 10 #define MP make_pair 11 #define REP(i, a, b) for (int i = a; i <= b; ++i) 12 #define FOR(i, a, b) for (int i = a; i < b; ++i) 13 14 #define mod 100007 15 16 int dp[1005][1005]; 17 char s[1005]; 18 19 int F(int l, int r) { 20 if (dp[l][r] != -1) return dp[l][r]; 21 if (l > r) return dp[l][r] = 0; 22 if (l == r) return dp[l][r] = 1; 23 int& ret = dp[l][r]; 24 ret = (F(l + 1, r) + F(l, r - 1)) % mod; 25 if (s[l] == s[r]) ++ret; 26 else ret -= F(l + 1, r - 1); 27 ret = (ret + mod) % mod; 28 return ret; 29 } 30 31 int main() 32 { 33 int cas = 0, t; 34 35 scanf("%d", &t); 36 while (t--) { 37 memset(dp, -1, sizeof(dp)); 38 scanf("%s", s + 1); 39 int ans = F(1, strlen(s + 1)); 40 printf("Case #%d: %d ", ++cas, ans); 41 } 42 return 0; 43 }
我的思路复杂度不好,T了
1 #include <cstdio> 2 #include <cstring> 3 #include <stack> 4 #include <vector> 5 #include <algorithm> 6 #include <queue> 7 #include <map> 8 #include <string> 9 #include <cmath> 10 11 #define ll long long 12 int const N = 1005; 13 int const M = 205; 14 int const INF = 0x7fffffff; 15 int const mod = 100007; 16 17 using namespace std; 18 19 int T,cnt; 20 int dp[N][N]; 21 char s[N]; 22 int l; 23 int ans; 24 25 void ini() 26 { 27 scanf("%s",s+1); 28 l=strlen(s+1); 29 memset(dp,-1,sizeof(dp)); 30 } 31 32 int dfs(int st,int en) 33 { 34 if(dp[st][en]!=-1) return dp[st][en]; 35 if(st>en){ 36 return dp[st][en]=0; 37 } 38 if(st==en){ 39 return dp[st][en]=1; 40 } 41 dp[st][en]=dfs(st,en-1)+1; 42 // printf(" st=%d en=%d dp=%d ",st,en,dp[st][en]); 43 44 int i; 45 for(i=st;i<en;i++){ 46 if(s[i]==s[en]) 47 dp[st][en]=(dp[st][en]+dfs(i+1,en-1)+1)%mod; 48 } 49 return dp[st][en]; 50 } 51 52 void solve() 53 { 54 ans=dfs(1,l); 55 } 56 57 void out() 58 { 59 /* 60 int i,j; 61 for(i=1;i<=l;i++){ 62 for(j=i;j<=l;j++){ 63 printf(" i=%d j=%d dp=%d ",i,j,dp[i][j]); 64 } 65 }*/ 66 printf("Case #%d: %d ",cnt,ans); 67 } 68 69 int main() 70 { 71 //freopen("data.in","r",stdin); 72 scanf("%d",&T); 73 for(cnt=1;cnt<=T;cnt++) 74 // while(T--) 75 //while(scanf("%d%d",&n,&m)!=EOF) 76 { 77 ini(); 78 solve(); 79 out(); 80 } 81 82 return 0; 83 }