链接:https://ac.nowcoder.com/acm/problem/21587
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
我们称正着读与反着读一样的串为回文串,比如abba与racecar都是回文串
我们称长度为奇数的回文为奇回文,中间的字符称为回文中心
有一个字符串S包含N个小写字母
令x[i]表示以i为回文中心的回文子序列的个数 (0 <= i <= N-1)
换句话说:保留第i个字符,X[i]表示有多少种字符的删除方案可以使得剩下的字符是一个以i为中心的回文串
Y[i] = ((i+1) * X[i])%1000000007
返回所有Y的xor之和
所有字母都是小写字母
输入描述:
输入一行包含一个字符串,字符串的长度(1 <= N <= 3000)
输出描述:
输出一个整数
示例1
输入
复制
axbcba
输出
复制
31
示例2
输入
复制
eeeee
输出
复制
14
示例3
输入
复制
zyzyzzzzxzyz
输出
复制
221
示例4
输入
复制
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
输出
复制
1044407608
备注:
子任务1:n<=100
子任务2:n<=500
子任务3:n<=3000
思路和心得:
(一)二维dp
1.需要dp,求两个端点的,左右两端的,能形成回文子序列的数量
2.枚举mid,作为奇回文子序列的中心
也可以看做是枚举l,每次只计算以为中心的情形
3.由于dp递推关系式,决定了r的遍历顺序是从右往左
4.每当。对于这个来说。我可以配合右侧所有的情形,也可以不和右侧的配合 就
5.而,是r指针从右往左的 的情况数
是方便计算用的
6.对于来说。它作为中心点的回文子序列情形,是把 这个区间作为右端点的情形都 加一遍。
7.python3 TLE 我也还没想到好的办法
python3代码
MOD = 10 ** 9 + 7 s = input() n = len(s) x = [1 for _ in range(n)] dp = [[0 for _ in range(n)] for _ in range(n)] for l in range(0, n - 1): mid = l + 1 right_acc = 0 for r in range(n - 1, mid, -1): dp[l][r] = dp[l - 1][r] if 0 <= l - 1 else 0 if s[l] == s[r]: dp[l][r] = (dp[l][r] + right_acc + 1) % MOD right_acc = (right_acc + dp[l - 1][r] if 0 <= l - 1 else 0) % MOD for r in range(n - 1, mid, -1): x[mid] = (x[mid] + dp[l][r]) % MOD # print(x) res = 0 for i in range(n): res ^= ((i + 1) * x[i]) % MOD print(res)
c++代码
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int MOD = 1e9 + 7; int main() { string s; cin >> s; int n = s.size(); long long x[n]; for (int i = 0; i < n; i ++) x[i] = 1; long long dp[n][n]; memset(dp, 0, sizeof(dp)); for (int l = 0; l < n - 1; l ++) { int mid = l + 1; long long right_acc = 0; for (int r = n - 1; r > mid; r --) { dp[l][r] = (0 <= l - 1 ? dp[l - 1][r] : 0); if (s[mid - 1] == s[r]) dp[l][r] = (dp[l][r] + right_acc + 1) % MOD; right_acc = (right_acc + (0 <= l - 1 ? dp[l - 1][r] : 0)) % MOD; } for (int r = n - 1; r > mid; r --) { x[mid] = (x[mid] + dp[l][r]) % MOD; } } long long res = 0; for (int i = 0; i < n; i ++) { res ^= ((i + 1) * x[i]) % MOD; } cout << res << endl; return 0; }
java代码
import java.util.* ; public class Main { public static void main(String [] args) { long MOD = (long)(1e9 + 7); Scanner scan = new Scanner(System.in); String s = scan.next(); int n = s.length(); long [] x = new long [n]; Arrays.fill(x, 1); long [][] dp = new long [n][n]; for (int l = 0; l < n - 1; l ++) { int mid = l + 1; long right_acc = 0; for (int r = n - 1; r > mid; r --) { dp[l][r] = (0 <= l - 1 ? dp[l - 1][r] : 0); long old = dp[l][r]; if (s.charAt(l) == s.charAt(r)) dp[l][r] = (dp[l][r] + right_acc + 1) % MOD; right_acc = (right_acc + (0 <= l - 1 ? dp[l - 1][r] : 0)) % MOD; } for (int r = n - 1; r > mid; r --) x[mid] = (x[mid] + dp[l][r]) % MOD; } long res = 0; for (int i = 0; i < n; i ++) { res ^= ((i + 1) * x[i]) % MOD; } System.out.println(res); } }