被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]
- 对于第k个位置的字符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; }