被3乘除的子序列

简介: 被3乘除的子序列


这个题目开始拿到手上不知道怎么设置状态转移,很多博客也没解释为什么那样转换是可以的。

首先我们要在数学上弄明白:mod 3,是非常特殊的,因为10%3=1,这有什么用呢。

如果目前1-i-1的某个子序列此时为x,取余3为k1,i位置数,取余3为k2,如果加上i位置的数的影响此时:

这个数就要变成10*x+a[i],对这个数取模mod:

(10*x xx+a [ i ] a[i]a[i])%m o d modmod=((10%m o d modmod)∗ *(x xx*%m o d modmod)+a [ i ] a[i]a[i]%m o d modmod)%m o d modmod

当 m o d = 3 , 因 为 10 m o d 3 = 1 , 所 以 上 式 等 于 ( x + a [ i ] ) 当mod=3,因为10mod3=1,所以上式等于(x+a[i])mod=3,10mod3=1,x+a[i])%m o d modmod

所以当(x%mod+a[i]%mod)=0时就是答案的转移

dp[i][0]是前i个数子序列组成数字的所有能除3为0的集合的元素的个数, dp[i][1],dp[i][2]同理。

考虑dp[i+1][j]对应的集合中的元素(子序列),其构成可以分为如下三类:

只包括前i个数,即dp[i][j]对应的集合中所有元素都是满足的

只包括第i+1个数,这时要考虑第i+1个数mod 3的余数是多少,若为j则可为这个dp[i+1][j]对应的集合加把劲儿,否则不行。

包括第i+1个数,也包括前i+1个数。可以通过选出dp[i][k]对应集合的每一个元素,在后面添加第i+1个数,为看使得新构造的子序列mod 3 结果为j, k应该满足(k+A[i+1])%3应该为j.

上代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 60, mod = 1e9 + 7;
ll dp[N][3];
string s;
int main() {
  cin >> s;
  dp[0][(s[0] - '0') % 3] = 1;
  int len = s.size();
  for (int i = 1; i < len; i++) {
    int m = (s[i] - '0') % 3;
    dp[i][m] = (dp[i][m] + 1) % mod; //单独kan i
    //在看 前i-1
    //最后看考虑 i的影响
    for (int j = 0; j < 3; j++) {
      dp[i][j] = (dp[i - 1][j] + dp[i - 1][(j - m + 3) % 3] + dp[i][j]) % mod;
    }
  }
  cout << dp[len - 1][0] % mod << "\n";
  return 0;
}
目录
相关文章
|
9月前
|
算法 C++
【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目
【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目
|
9月前
|
机器学习/深度学习 算法 测试技术
【动态规划】【最长子序列】2901. 最长相邻不相等子序列 II
【动态规划】【最长子序列】2901. 最长相邻不相等子序列 II
|
9月前
|
人工智能 算法 测试技术
【动态规划】【字符串】【C++算法】940. 不同的子序列 II
【动态规划】【字符串】【C++算法】940. 不同的子序列 II
【动态规划刷题 15】最长定差子序列&& 最长的斐波那契子序列的长度
【动态规划刷题 15】最长定差子序列&& 最长的斐波那契子序列的长度
|
9月前
|
存储
leetcode-940:不同的子序列 II
leetcode-940:不同的子序列 II
41 0
|
9月前
leetcode-115:不同的子序列
leetcode-115:不同的子序列
40 0
|
9月前
leetcode-516:最长回文子序列
leetcode-516:最长回文子序列
45 0
|
算法 C++ Python
每日算法系列【LeetCode 115】不同的子序列
每日算法系列【LeetCode 115】不同的子序列
|
算法 程序员
最大的子序列和的问题:
最大的子序列和的问题:
最大的子序列和的问题: