21302被3整除的子序列
题目描述
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
输入描述:
输入一个字符串,由数字构成,长度小于等于50
输出描述:
输出一个整数
示例1
输入 132
输出 3
示例2
输入 9
输出 1
示例3
输入 333
输出 7
示例4
输入 123456
输出 23
示例5
输入 00
输出 3
备注:
n为长度
子任务1: n <= 5
子任务2: n <= 20
子任务3: 无限制
思路简析
本题分为两个层次思考即可
第一层:单个数字能否被3整除,第二层:组合数字能否被3整除。
用字符串s存储数字,然后计算时用(s[i]-‘0’)把字符转换为数字即可,用dp[i][j]表示到前i个字符能凑出余数为j的个数,第二层满足dp[i][j]的情况包含:
①dp[i-1][j](即前i-1位数字和已经能够被3整除,这部分个数应计入最终的结果)
②dp[i-1][(j+3-m)%3](即为前i-1位数字虽然不能被3整除,但是前面i-1位数字和对3取模与最后一位数相加正好拼成3的倍数)
举一个例子:132这个数,先按照第一层遍历一遍,即s[0]=1,s[1]=3,s[2]=2三个单独的数字,前1位和为1,前两位和为4(对3取模后余1),前三位和为6(对3取模后余0),则给相应的dp[1][1],dp[2][1],dp[3][0]分别加1。其次组合数字13,32,12,132,其中12满足所说的第①种情况,132满足所说的第②种情况,所以最终答案为3个。
源代码
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
long long dp[55][3];// dp[i][j]表示到前i个字符能凑出余数为j的个数
int main()
{
string s;
cin>>s;
int len = s.length();
for(int i = 1;i<=len;i++)
{
int m = (s[i-1]-'0')%3;
dp[i][m] = (dp[i][m]+1)%mod;
for(int j = 0;j<3;j++)
{
//两种情况相加
dp[i][j] += (dp[i-1][j]+dp[i-1][(j+3-m)%3])%mod;
}
}
cout<<dp[len][0]<<endl;
return 0;
}