区间DP
原理:余数相加
题解:有点像背包问题,对于每个数字要么选要么不选,用dp全部枚举出来,计算可以被3整除的个数。
#include<iostream>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstring>
#include<string>
#include<cstdio>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
const int N=2e6+10;
typedef long long ll;
char vis[20000];
char a[20000];
ll dp[20000][5];//保存从0到i上,余数为0,1,2的子序列数目
int ans;
ll mod=1e9+7;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
string num;
cin>>num;
int n=num.length();
for(int i=0;i<n;i++)
{
dp[i][(num[i]-'0')%3]=1;
}
for(int i=0;i<n;i++)
{
if(num[i]%3==0)
{
dp[i][0]=2*dp[i-1][0]+1;//自己本身为子序列所以加一
dp[i][1]=2*dp[i-1][1];
dp[i][2]=2*dp[i-1][2];
}
else if(num[i]%3==1)
{
dp[i][0]=dp[i-1][0]+dp[i-1][2];
dp[i][1]=dp[i-1][1]+dp[i-1][0]+1;
dp[i][2]=dp[i-1][2]+dp[i-1][1];
}
else if(num[i]%3==2)
{
dp[i][0]=dp[i-1][0]+dp[i-1][1];
dp[i][1]=dp[i-1][1]+dp[i-1][2];
dp[i][2]=dp[i-1][2]+dp[i-1][0]+1;
}
for(int j=0;j<3;j++) dp[i][j]%=mod;//取余
}
cout<<dp[n-1][0]<<endl;
}