zoukankan      html  css  js  c++  java
  • abc214_f Substrings(dp)

    题目链接

    题目大意

      给你一个字符串,你可以标记一个子序列,子序列中的字符不能相邻,剩下的删除掉,问最后能形成多少种不同的子序列。

    解题思路

      可以设dp[i]表示以i结尾并且最后剩下的子序列有第i位时有多少不同的子序列。设dp[1] = dp[0] = 1, 那么我们的状态转移方程就是(dp[i] = sum dp[j](j leq i-2))。但是这样时有重复计算的,给一个字符串"abcabc",当i处于第2个'c'的位置时,我们的状态计算为dp[6] = dp[4]+dp[3]+dp[2],发现不能再加dp[1]了,因为这相当于"ac"这个子序列,但是之前计算第1个'c'的位置时就已经计算过"ac"了,再计算就重复了,也就是说如果j+1和i相等的话,j就不应该再往前枚举了。
      这就结束了吗?还没完,比如"aaaaaa",计算第一个'a'的时候贡献为1,计算第二个'a'的时候贡献也为1,是不是不太对?前两个对应的子序列都是'a',明显重复了。这时候我们可以在字符串前面加一个奇怪的符号,等于说计算的字符串整体右移了一个字符,然后只让dp[0]初始化为1,从2开始计算,在j+1和i相等的时候,j就不再往前枚举了,就可以避免重复计算了。

    const int maxn = 2e5+10;
    const int maxm = 2e5+10;
    ll dp[maxn];
    int main(void) { 
        IOS;
        string s; cin >> s;
        s = "&^"+s;
        dp[0] = 1;
        int n = s.size();
        for (int i = 2; i<n; ++i) {
            for (int j = i-2; j>=0; --j) {
                dp[i] = (dp[i]+dp[j])%MOD;
                if (s[j+1]==s[i]) break;
            }
        }
        ll sum = 0;
        for (int i = 2; i<n; ++i) sum = (sum+dp[i])%MOD;
        cout << sum << endl;
    	return 0;   
    }
    
  • 相关阅读:
    27. Remove Element
    26. Remove Duplicates from Sorted Array
    643. Maximum Average Subarray I
    674. Longest Continuous Increasing Subsequence
    1. Two Sum
    217. Contains Duplicate
    448. Find All Numbers Disappeared in an Array
    566. Reshape the Matrix
    628. Maximum Product of Three Numbers
    UVa 1349 Optimal Bus Route Design (最佳完美匹配)
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15158728.html
Copyright © 2011-2022 走看看