被3整除的子序列(闫氏DP分析法)

题目链接:https://ac.nowcoder.com/acm/problem/21302

核心思路:类似于01背包问题

  • 状态表示:
    • dp[i][j]:仅仅由前i个字符组成,且和为j的方案总数
  • 状态属性:
    • 单纯求出每一个dp[i][j]即可
  • 状态计算:
    • 对于第k个位置的字符x,有两种方案:选与不选
      • 不选第k个位置的字符:dp[i][j] = dp[i - 1][j]
      • 选第k个位置的字符:dp[i][j] = dp[i][j] + dp[i - 1][j - x]

最后的答案应该是所有j为3的倍数的dp[length][j]之和

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll dp[55][550];

int main() {
    string s;    cin >> s;
    s = ' ' + s;
    for(int i = 1; i < s.size(); i++)
        for(int j = 0; j <= 450; j++) {
            dp[i][j] = dp[i - 1][j];
            int x = s[i] - '0';
            if(j == x) dp[i][j]++;
            if(j >= x) dp[i][j] = (dp[i][j] + dp[i - 1][j - x] + mod) % mod;
        }
    ll res = 0;
    for(int i = 0; i <= 450; i++) 
        if(i % 3 == 0)
            res = (res + dp[s.size() - 1][i] + mod) % mod;
    cout << res % mod << endl;
    return 0;
}

  

posted @ 2021-02-06 22:15  ACM-Epoch  阅读(86)  评论(0编辑  收藏  举报