• 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;   
    }
    
  • 相关阅读:
    技术晨读_2015_11_29
    mysql的timeout
    Gradle目录解析
    flexbox简介
    elasticsearch 查询(match和term)
    内存那些事
    elasticsearch 文档
    elasticsearch 集群
    elasticsearch中的API
    小菜的程序员道路(三)
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15158728.html
Copyright © 2020-2023  润新知