题目
题目描述
给你一个长度为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: 无限制
思路
这个题是一个典型的动态规划问题,与背包问题类似
解决动态规划题我大致分为三个步骤:
找规律
转移方程
初始条件和边界情况
题解
首先分析题目,这个题的大致意思就是给一串数字,类似798,然后找出这个字串的所有子序列,相当于就是{7,8,9,78,79,89,798},然后找出这些字串中能被3整除的数量,798返回的就是3
然后找到第一个规律,79的子串是{7,9,79},在后面加一个8,就相当于79的子串&79的子串每一项都“加上”一个8,即{7,9,79,78,98,798,8}
然后就是第二个规律,79的字串中每一项%3所得出的结果中0,1,2的数量分别为{1,0,1},798的结果为{1,0,1,0,2,0,2},因为8%3=2,然后这个字串%3的结果可以看作{1,0,1,(1+8%3)%3,(0+8%3)%3,(1+8%3)%3,8%3}
然后可以推断出这个题是一个链式结构,随着字符的遍历,子串的长度一直递增,可以推断出转移方程dp[i][j] =dp[i][j]+ dp[i - 1][j] + dp[i - 1][(j + 3 - temp) % 3]
代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
int len = s.length();
int mod = (int) (1e9 + 7);
int[][] dp = new int[50][3];
dp[0][s.charAt(0) % 3] = 1;
for (int i = 1; i < len; i++) {
int temp = s.charAt(i) % 3;
dp[i][temp] = (dp[i][temp] + 1) % mod;
for (int j = 0; j < 3; j++) {
dp[i][j] += (dp[i - 1][j] + dp[i - 1][(j + 3 - temp) % 3]) % mod;
}
}
System.out.println(dp[len - 1][0] % mod);
}
}