牛客_21302被3整除的子序列_动态规划

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_45619006/article/details/114548508
今日推荐