zoukankan      html  css  js  c++  java
  • HDU 4632 Palindrome subsequence & FJUT3681 回文子序列种类数(回文子序列个数/回文子序列种数 容斥 + 区间DP)题解

    题意1:问你一个串有几个不连续子序列(相同字母不同位置视为两个)

    题意2:问你一个串有几种不连续子序列(相同字母不同位置视为一个,空串视为一个子序列)

    思路1:由容斥可知当两个边界字母相同时 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1;当两个字母不同时 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]。然后区间DP即可

    思路2:由思路1我们能大致知道怎么做,显然两边界字母不一样时情况是一样的。当两边字母一样时,那么就要判断中间的重复情况。

    我们设l和r,表示i + 1 ~ j - 1里最左边的s[i]字母和最右边的s[i]字母

    当 l == r 那么就只有一个相同字母,dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1,答案为中间部分 + 中间加上两边界 + s[i]s[j]串

    当 l > r,没有这个字母,dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] + 2,答案为中间部分 + 中间加上两边界 + s[i]s[j]串 + s[i]

    当l < r,说明至少有两个字母,dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] - dp[l + 1][r - 1],答案为中间部分 + 中间加上两边界 - (l,r)区间内种数,因为这里面的和s[l],s[r]组成的串和s[i],s[j]重复

    代码1:

    #include<set>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    typedef long long ll;
    using namespace std;
    const int maxn = 1e3 + 10;
    const ll MOD = 1e4 + 7;
    const int INF = 0x3f3f3f3f;
    int dp[maxn][maxn]; //i到j种数
    char s[maxn];
    int main(){
        int t, ca = 1;
        scanf("%d", &t);
        while(t--){
            scanf("%s", s + 1);
            int n = strlen(s + 1);
            for(int i = 1; i <= n; i++){
                dp[i][i] = 1;
            }
            for(int len = 2; len <= n; len++){
                for(int i = 1; i + len - 1 <= n; i++){
                    int j = i + len - 1;
                    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][j - 1] - dp[i + 1][j - 1];
                    }
                    dp[i][j] = (dp[i][j] + MOD) % MOD;
                }
            }
            printf("Case %d: %d
    ", ca++, dp[1][n]);
        }
        return 0;
    }

    代码2:

    #include<set>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    typedef long long ll;
    using namespace std;
    const int maxn = 1e3 + 10;
    const ll MOD = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    ll dp[maxn][maxn]; //i到j种数
    char s[maxn];
    int main(){
        int t, ca = 1, n;
        scanf("%d", &t);
        while(t--){
            scanf("%s", s + 1);
            int n = strlen(s + 1);
            for(int i = 1; i <= n; i++){
                dp[i][i] = 1;
            }
            for(int len = 2; len <= n; len++){
                for(int i = 1; i + len - 1 <= n; i++){
                    int j = i + len - 1;
                    if(s[i] == s[j]){
                        int l = i + 1, r = j - 1;
                        while(s[l] != s[i] && l <= r) l++;
                        while(s[r] != s[i] && l <= r) r--;
                        if(l > r){
                            dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] + 2;
                        }
                        else if(l == r){
                            dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1;
                        }
                        else{
                            dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] - dp[l + 1][r - 1];
                        }
                    }
                    else{
                        dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1];
                    }
                }
            }
            printf("Case %d: %lld
    ", ca++, dp[1][n]);
        }
        return 0;
    }
  • 相关阅读:
    HTML5之dir属性
    IPv4地址分类及子网划分
    二叉树的3种遍历
    js的点表示法和方括号表示法
    javascript-数组的常用方法
    第一编博文——漫长编程路
    使用qemu
    initial ram disk
    qemu常见选项解析
    cp和scp
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10505714.html
Copyright © 2011-2022 走看看