非曰能,但好学。欢迎一起交流学习

问题分析

动态规划问题,定义好动态变量则成功了一半,找到变量的迭代关系怎成功一大半。

动态变量

变量定义,在adoptions的题解已经提及,引用如下

我们定义dp[i][j]为前i个中整除3余数为j(只有0,1,2三个数)的个数

我再啰嗦得解释一下,dp[i][0]是前i个数包好的所有能除3为0的集合的元素的个数, dp[i][1],dp[i][2]同理。我个人觉得在集合的概念下,考虑递推比较方便。

迭代关系

设给定的数列为,这里我对迭代关系说明一下。假设我们已经有了 ,考虑新来了第i+1个数,怎么计算.
考虑dp[i+1][j]对应的集合中的元素(子序列),其构成可以分为如下三类:

  1. 只包括前i个数,即dp[i][j]对应的集合中所有元素都是满足的
  2. 只包括第i+1个数,这时要考虑第i+1个数mod 3的余数是多少,若为j则可为这个dp[i+1][j]对应的集合加把劲儿,否则不行。
  3. 包括第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;

class Solution
{
    public:
    vector<int> A;
    vector<long long> dp;
    void read()
    {
        string s;
        getline(cin,s);
        A = vector<int>(s.size());
        //cout<<s<<endl;
        for(int i=0; i<s.size(); i++)
            A[i]=s[i]-'0';
    }

    void process()
    {
        dp = vector<long long>(3);
        read();
        for(int i=0; i<A.size(); i++)
        {
            long long atmp[3];
            for(int ind=0; ind<3; ind++)
                atmp[ind] = (dp[ind] + dp[(ind-A[i]%3+3)%3])%1000000007;
            for(int ind=0; ind<3; ind++)
                dp[ind] = atmp[ind];
            dp[A[i]%3]++;
        }
        cout<<dp[0]<<endl;
    }
};

int main()
{
    Solution s;
    s.process();
    return 0;
}