zoukankan      html  css  js  c++  java
  • wap网测一道题目

    1. 给定一个字符串s, 1 <= len(s) <= 3000, 定义odd palindrome string为长度为奇数的回文串, 求s中该奇回文串的个数。

    比如axbcba , 结果为12.

    实在想不出来该怎么做,想到一个笨办法,但是tle。 考察左边a对回文串的贡献, 它依次跟右边的a配对,使得这两个a之间的奇回文串翻倍,然后做记忆化搜索。

     1 #include<bits/stdc++.h>
     2 #define pb push_back
     3 typedef long long ll;
     4 using namespace std;
     5 typedef pair<int, int> pii;
     6 const int maxn = 1e3 + 10;
     7 const int mod = 1e9 + 7;
     8 
     9 ll dp[3010][3010];
    10 string s;
    11 ll work(int x, int y) {
    12     if(x > y) return 0;
    13     if(x == y) return 1;
    14     ll& res = dp[x][y];
    15     if(res != 0) return res;
    16     res++;
    17     for (int j = y; j > x; j--) {
    18         if(s[j] == s[x]) {
    19             res  = (res + work(x + 1, j - 1)) % mod;
    20         }
    21     }
    22     res = (res + work(x + 1, y)) % mod;
    23     return res;
    24 }
    25 void solve() {
    26     for (int i = 0; i < 3000; i++) {
    27         s += (char) ('a' + i % 26);
    28     }
    29     //cin >> s;
    30     cout << s << endl;
    31     cout << work(0, s.size() - 1) << endl;
    32 }
    33 
    34 int main() {
    35     freopen("test.in", "r", stdin);
    36     //freopen("test.out", "w", stdout);
    37     ios::sync_with_stdio(0);
    38     cin.tie(0); cout.tie(0);
    39     solve();
    40     return 0;
    41 }
    View Code

    问了下,同学的方法,解法比较巧妙。对每一个字符,求左右2边的相同子序列的个数。寻找递推方程。

     1 int dp[3010][3010];
     2 int solve(string s) {
     3     int n = s.size(), res = 0;
     4     memset(dp, 0, sizeof(dp));
     5     for(int i = 1; i <= n; i++){
     6         for(int j = n; j > i; j--){
     7             if(s[i-1] == s[j-1]){
     8                 dp[i][j] = (dp[i-1][j] + dp[i][j+1] + 1) % MOD;
     9             }
    10             else{
    11                 dp[i][j] = ((dp[i-1][j] + dp[i][j+1])%MOD +(1000000007- dp[i-1][j+1]) )%MOD;
    12             }
    13         }
    14     }
    15     for(int i = 1; i <= n; i++){
    16         res = ((res + dp[i-1][i+1])%MOD  + 1) % MOD;
    17     }
    18     return res;
    19 }
    View Code

    看了这个解法,我就感觉有点在哪里见过的赶脚, 然后想到以前做过的一道题, 数字符串s里面回文子序列的个数。

    就是这个题目:https://hihocoder.com/problemset/problem/1149 当时什么都不懂, 现在大概有点想法了。

    这个题目的代码如下:

     1 #include<bits/stdc++.h>
     2 #define pb push_back
     3 typedef long long ll;
     4 using namespace std;
     5 typedef pair<int, int> pii;
     6 const int maxn = 1e3 + 10;
     7 const int mod = 100007;
     8 ll dp[1010][1010];
     9 char s[1010];
    10 void solve() {
    11     scanf("%s", s);
    12     memset(dp, 0, sizeof dp);
    13     int n = strlen(s);
    14     for (int j = 1; j <= n; j++) {
    15         for (int i = 1; i <= n; i++) {
    16             int r = i + j - 1;
    17             if(j == 1) {
    18                 dp[i][r] = 1;
    19             } else {
    20                 if(s[i - 1] == s[r - 1]) {
    21                     dp[i][r] = (dp[i][r - 1] + dp[i + 1][r] + 1) % mod;
    22                 } else {
    23                     dp[i][r] = ((dp[i][r - 1] + dp[i + 1][r] - dp[i + 1][r - 1]) % mod + mod) % mod;
    24                 }
    25             }
    26         }
    27     }
    28     printf("%lld
    ", dp[1][n]);
    29 }
    30 
    31 int main() {
    32     freopen("test.in", "r", stdin);
    33     //freopen("test.out", "w", stdout);
    34     //ios::sync_with_stdio(0);
    35     //cin.tie(0); cout.tie(0);
    36     int _;
    37     scanf("%d", &_);
    38     for (int i = 1; i <= _; i++) {
    39         printf("Case #%d: ", i);
    40         solve();
    41     }
    42     return 0;
    43 }
    View Code

    然后,我就想着,这道题目能不能这样做呢, 其实也是可以的。

    定义dp[i][j],为区间[i. j]奇回文的个数, 显然长度为1的时候为1, 长度为2的时候为2, 然后转移方程就跟上面的hihocode回文子序列的个数差不多了。

     1 #include<bits/stdc++.h>
     2 #define pb push_back
     3 typedef long long ll;
     4 using namespace std;
     5 typedef pair<int, int> pii;
     6 const int maxn = 1e3 + 10;
     7 const int mod = 1e9 + 7;
     8 string s;
     9 ll dp[3010][3010];
    10 void solve() {
    11     for (int i = 0; i < 3000; i++) {
    12         s += (char) ('a' + i % 26);
    13     }
    14     //cin >> s;
    15     cout << s << endl;
    16     int n = s.size();
    17     for (int i = 1; i <= n; i++) {
    18         for (int j = 1; j <= n; j++) {
    19             int l = j, r = j + i - 1;
    20             if(r > n) continue;
    21             if(i == 1) {
    22                 dp[l][r] = 1;
    23             } else if(i == 2){
    24                 dp[l][r] = 2;
    25             } else {
    26                 if(s[l - 1] == s[r - 1]) {
    27                     dp[l][r] = (dp[l + 1][r] + dp[l][r - 1]) % mod;
    28                 } else {
    29                     dp[l][r] = (dp[l + 1][r] + dp[l][r - 1] - dp[l + 1][r - 1] + mod) % mod;
    30                 }
    31             }
    32             //cout << l << " " << r << " " << dp[l][r] << endl;
    33         }
    34     }
    35     cout << dp[1][n] << endl;
    36 }
    37 
    38 int main() {
    39     freopen("test.in", "r", stdin);
    40     //freopen("test.out", "w", stdout);
    41     ios::sync_with_stdio(0);
    42     cin.tie(0); cout.tie(0);
    43     solve();
    44     return 0;
    45 }
    View Code

    以前不是很了解这种dp的套路,现在大概是有点想法了。

  • 相关阅读:
    网站跨站点单点登录实现--cookie
    sql order by 排序多个字段
    JAVA字符串格式化-String.format()的使用
    Cent OS 常用配置命令
    键盘事件keydown、keypress、keyup随笔整理总结
    Chrome 开发者工具使用技巧
    JS打开新窗口防止被浏览器阻止的方法[转]
    javaBean与map类型相互转换
    【转载】 自动化机器学习(AutoML)之自动贝叶斯调参
    国内还不错的量化交易平台
  • 原文地址:https://www.cnblogs.com/y119777/p/6950340.html
Copyright © 2011-2022 走看看