题目描述
给你一个长度为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整除。
- 同余与模算术:(a+b) mod n=((a mod n)+(b mod n)) mod n。
- 综合前面两点,可以得出把字符串的和取模3,处理成 每个数字取模3,再将它们的和取模3,那么每个数字的结果只有0 ,1 ,2这三种情况。
算法(动态规划)
二维数组dp[i] [j] 表示 前 i 个长度的所有子序列数位数字和取模 3 为 j 的数目( 0 <= j < 3)
有状态转移方程 :dp[i] [j] = (dp[i - 1] [j] + dp[i - 1] [ (j - m + 3) % 3]) % (1e9+7);
m=第i个数字取模3的结果。
实例:j=0 时,表示能被3整除。
dp[i] [0]可以由两种情况递推过来:
1. 第 i 个数字不用, 那么能被3整除的个数为 dp[i - 1] [0]。
2. 第 i 个数字与前边(i-1)个数字相接,即前(i-1)数字的和与i相加能被3整除的个数,即满足和为 ( j - m + 3) % 3 的所有子序列。
dp[i] [0] = (dp[i - 1] [0] + dp[i - 1] [ (0 - m + 3) % 3]) % (1e9+7);
最后这个数字自己构成长度为 1 的子序列单独加上。
代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
double mod = 1e9 + 7;//结果取余
while (in.hasNext()) {
String str = in.nextLine();
int[][] dp = new int[51][3];//因为数组从0开始,而i代表是有多少数,所以第50个数数组代表的是51
for (int i = 1; i <= str.length(); i++) {
int m = (str.charAt(i - 1) - '0') % 3;//数字对3取模
for (int j = 0; j < 3; j++) {
dp[i][j] = (int) ((dp[i - 1][j] + dp[i - 1][(j - m + 3) % 3]) % mod);//+3表示结果是非负的
}
dp[i][m] = (int) ((dp[i][m] + 1) % mod);//当前数字符合取模则自增
}
System.out.println(dp[str.length()][0]);
}
in.close();
}
}