题目是DP,所以看完题目就想着找递推式
一.首先dp数组表示什么,一开始看完有两种想法:
- dp[i]表示长度为i的满足子序列(为了表达简单,满足被三整除的子序列简称为满足子序列)个数
- dp[i]表示主串中前i个元素可以构成的所有子序列
二. 然后开始找递推关系 不论是1还是2,它们的递推都是在一个字串上添加上一个元素,所以要先搞清楚添加一个元素后前后的数值变化,来建立递推关系 首先有两个性质:
- 对于3的倍数(可以被三整除的数)其各个位上数字之和为3的倍数
- 当两个数相加取余时满足分配律(这里表达可能有点问题)。即对整数a、b,若a%3=m,b%3=n;那么则(a+b)%3=(a%3+b%3)%3=(m+n)%3;
根据性质1,我们添加一个元素a后是否为三的倍数,只用看+a后是否为3的倍数
而+a后是否为3的倍数,就可以用性质2来连接前后了
即+a后是否为3的倍数,只用看a%3+b%3(假设原本字串和为b)%3是否为0了,
那么就只有三种情况: 1.a%3==0且b%3==0; 2.a%3==1且b%3==2; 3a%3==2且b%3==1; 这样就建立了前后的递推关系 代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(void)
{
char s[50+2];
cin>>s;
int len=strlen(s);
long long dp[50+2][3];//dp[i][j]表示含前i个数字的子序列可以被三整除余j的个数
dp[0][0]=0;
dp[0][1]=0;
dp[0][2]=0;
for(int i=0;i<len;i++)
{
//注意要同时记录%3==1,%3==2的个数
if((s[i]-'0')%3==0)
{
dp[i+1][0]=dp[i][0]+dp[i][0]+1;
dp[i+1][1]=dp[i][1]+dp[i][1];
dp[i+1][2]=dp[i][2]+dp[i][2];
}
else if((s[i]-'0')%3==1)
{
dp[i+1][0]=dp[i][0]+dp[i][2];
dp[i+1][1]=dp[i][1]+dp[i][0]+1;
dp[i+1][2]=dp[i][2]+dp[i][1];
}
else if((s[i]-'0')%3==2)
{
dp[i+1][0]=dp[i][0]+dp[i][1];
dp[i+1][1]=dp[i][1]+dp[i][2];
dp[i+1][2]=dp[i][2]+dp[i][0]+1;
}
}
int mod=1e9+7;
cout<<dp[len][0]%mod;
return 0;
}