题目
hdu4632
题意:
输出字符串中所有子序列回文串(可以不连续)的个数。
as:aaa的所有子序列回文串是a(0),a(1),a(2),a(0)a(1),a(1)a(2),a(0)a(2),a(0)a(1)a(2) (括号里面的数字是这个字符在字符串中的坐标)
思路:
在区间i ~ j 中,
如果a [ i ] != a [ j ],dp [ i ] [ j ] = dp [ i + 1 ] [ j ] + dp [ i ][ j - 1 ] - dp [ i + 1] [ j - 1]
as:在字符串aaab中,(相同的用粗体表示)
dp [ i ] [ j - 1 ] = 7 【a(0),a(1),a(2),a(0)a(1),a(1)a(2),a(0)a(2),a(0)a(1)a(2)】
dp [ i + 1 ] [ j ] = 3 【a(1),a(2),a(1)a(2)】
dp [ i + 1] [ j - 1] = 3 【a(1),a(2),a(1)a(2)】
dp [ i ] [ j ] = 7 + 3 - 3 = 7
如果a [ i ] = a [ j ],dp [ i ] [ j ] = dp [ i + 1 ] [ j ] + dp [ i ][ j - 1 ] - dp [ i + 1] [ j - 1] + 1 + dp [ i + 1] [ j - 1] => dp [ i + 1 ] [ j ] + dp [ i ][ j - 1 ] + 1
as:在字符串aaaa中,(相同的用粗体表示)
dp [ i ] [ j - 1 ] = 7 【a(0),a(1),a(2),a(0)a(1),a(1)a(2),a(0)a(2),a(0)a(1)a(2)】
dp [ i + 1 ] [ j ] = 7 【a(1),a(2),a(3), a(1)a(2),a(2)a(3),a(1)a(3),a(1)a(2)a(3)】
dp [ i + 1] [ j - 1] = 3 【a(1),a(2),a(1)a(2)】
1:【a(0)a(3)】
另一个dp [ i + 1] [ j - 1] = 3 【a(0)a(1)a(3),a(0)a(2)a(3),a(0)a(1)a(2)a(3)】
dp [ i ] [ j ] = 7 + 7 - 3 + 3 + 1 => 7 + 7 + 1
解法1:
#include <iostream>
#include <cstring>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
#define CASEE int t; cin >> t; for (int ti = 1; ti <= t; ti++)
using namespace std;
const int MAXN = 1010;
const int MOD = 10007;
char s[MAXN];
int dp[MAXN][MAXN];
void solve(){
scanf(" %s", s);
int lena = strlen(s);
for (int i = 0; i < lena; i++)
dp[i][i] = 1;
for (int len = 1; len < lena; len++)
for (int i = 0; i < lena - len; i++){
int j = i + len;
if (s[i] == s[j])
dp[i][j] = dp[i+1][j] + dp[i][j-1] + 1;
else
dp[i][j] = dp[i+1][j] - dp[i+1][j-1] + dp[i][j-1];
dp[i][j] = (dp[i][j] + MOD) % MOD; //有可能是负数(有减法)所有要+MOD
}
printf("%d\n", dp[0][lena-1]);
}
int main(){
CASEE{
printf("Case %d: ", ti);
solve();
}
return 0;
}
解法2:
#include <iostream>
#include <cstring>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
#define CASEE int t; cin >> t; for (int ti = 1; ti <= t; ti++)
using namespace std;
const int MAXN = 1010;
const int MOD = 10007;
char s[MAXN];
int dp[MAXN][MAXN];
void solve(){
scanf(" %s", s);
int lena = strlen(s);
for (int i = 0; i < lena; i++)
dp[i][i] = 1;
for (int i = lena - 1; i >= 0; i--)
for (int j = i + 1; j < lena; j++){
if (s[i] == s[j])
dp[i][j] = dp[i+1][j] + dp[i][j-1] + 1;
else
dp[i][j] = dp[i+1][j] - dp[i+1][j-1] + dp[i][j-1];
dp[i][j] = (dp[i][j] + MOD) % MOD; //有可能是负数(有减法)所有要+MOD
}
printf("%d\n", dp[0][lena-1]);
}
int main(){
CASEE{
printf("Case %d: ", ti);
solve();
}
return 0;
}