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;   
    }
    
  • 相关阅读:
    Java内部类
    sql几种连接的区别
    常见的十大算法
    使用yml文件配置数据库数据时的问题
    SpringBoot整合Mybatis
    不是书评 :《我是一只IT小小鸟》
    考试考完了·
    MSSQL站库分离情况的渗透思路
    VENOM cve-2015-3456 Qemu 虚拟机逃逸漏洞POC
    Python 实现指定目录下 删除指定大小的文件
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15158728.html
Copyright © 2011-2022 走看看