XTU OJ 1434 Lost Digits

Description

Lost Digits

题目描述

007获得了一张纸条,上面写了一个无前导0的十进制整数n,但是其中的一些数码已经被涂掉了。007知道这个数是7的倍数,他现在想知道有多少个数满足条件?

输入

第一行是一个整数T(1≤T≤1000)。 以后每行一个样例,为一个字符串,字符串长度不超过9位,只包含数字09,以及字符?,其中?表示涂掉的数码。

输出

每行输出一个样例的结果。

样例输入

2
7?
?7

样例输出

2
1

样例解释

第一个样例可以为70和77;第二个样例只能为77。

思路分析:这种题对于我这种小菜鸡算难的了,所以问了大佬,写了下自己的分析

首先,这道题肯定是要用数位DP来做,那么平常我们递推或者递归的时候肯定是找这一位和上一位之间的关系,这道题也是这样做的。这道题的条件是让我们统计能被7整除的数的数量,那么我们就去看第i位和第i-1位与7的余数有什么关系。假设已经输入了1234,那么余数为2,如果后面再加一位数,例如5,那么12345的除以7余数应该是2*10+5,为什么?不妨列出一个除法的式子出来,在对1234进行运算的时候,如果没有第5位为5,就会掉下来一个2,而如果说后面有一个5,是不是要继续算?那么在除法的式子后面就会继续跟上5,然后继续%7。综上所述,一个数加上第i位数能不能%7==0要看前面i-1位数的余数是多少,因此,我们就找到了一个递推关系,需要一个二维数组储存两个信息,第多少位数,二是前几位的余数。又因为,这个递推关系与你输入的字符串有很强的关系,所以每输入一次数据都需要递推。同时,在实现的过程中,我们如果只将余数是否为0的记入数组显然非常困难,由此我们自然而然想到不妨将所有余数情况全部存入,也就是说二维数组的第二个空位应当存储%7所有的余数情况,之后将需要的余数的情况调用即可

#include <stdio.h>
#include <string.h>
char s[10] = { 0 };
int dp[20][8] = { 0 };
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		memset(s, 0, sizeof(s));
		memset(dp, 0, sizeof(dp));
		scanf(" %s", s);
		int len = strlen(s);
		if (len == 1 && s[0] == '?') {
			printf("2\n");//注意0也是7的倍数
			continue;
		}
		if (s[0] != '?') {//处理开头部分,确定递归或者递推的起点
			dp[0][(s[0] - '0')%7]++;
		}
		else {
			for (int i = 0; i < 10; i++) {
				dp[0][i%7]++;
			}
			dp[0][0]--;//0别忘了
		}
		//上面是确定开头
		//然后就开始递推和递归了
		for (int i = 1; i <= len; i++) {//指针i遍历字符串
			//为了将前一位包含进去,所以我们i最大取len,这样就会包含进len-1了
			if (s[i] == '?') {//如果说是?那么我们0-9全部都遍历一遍
				for (int n = 0; n < 10; n++) {
					for (int j = 0; j < 7; j++) {//j是代表的余数!不可能>=7
						dp[i][(10 * j + n) % 7] += dp[i - 1][j];
					}
				}
			}
			else {
				for(int j  =0;j<7;j++)
				dp[i][(10 * j + (s[i] - '0'))%7] += dp[i - 1][j];
				//遍历上一位的余数的所有情况,然后结合第i位输入的数据存入数组当中
			}
		}
		printf("%d\n", dp[len-1][0]);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_24917263/article/details/127776959