X mod f(x)
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 994 Accepted Submission(s): 439
Problem Description
Here is a function f(x): int f ( int x ) { if ( x == 0 ) return 0; return f ( x / 10 ) + x % 10; }
Now, you want to know, in a given interval [A, B] (1 <= A <= B <= 10 9), how many integer x that mod f(x) equal to 0.
Input
The first line has an integer T (1 <= T <= 50), indicate the number of test cases.
Each test case has two integers A, B.
Each test case has two integers A, B.
Output
For each test case, output only one line containing the case number and an integer indicated the number of x.
Sample Input
2 1 10 11 20
Sample Output
Case 1: 10 Case 2: 3
这是我做的第一个数位dp,看了很多人的代码,都不是很懂,最后终于看懂了,太不容易了,其实这个是记忆化搜索更合适!
d[le][s][mod][r] 表示的是长度为le,前缀和为s,数字(就是f(x))mod,余数为r的数有几个。
由于输入的是上界和下界,所以考虑用find(上界)-find(下界)的方法,即find(x)表示1-x范围内符合条件的个数。
首先看f(x),由于x的范围限制,f(x)最大到81,所以选择枚举y=f(x)。
举个例子,比如上界为45678,则其长度为5,mod是我们要枚举的,r的最终目的是0
所以进入搜索的条件是要找dfs(5-1,0,i,0)
前缀和为0,就是说我们要找到前缀和等于mod的情况,只要前缀和等于mod 并且余数为0就是符合的。
长度为le的总是由长度为le-1的求出,不停的添加,直到和大于等于mod为止,在判断r是否为0.
d[le][s][mod][r] 表示的是长度为le,前缀和为s,数字(就是f(x))mod,余数为r的数有几个。
由于输入的是上界和下界,所以考虑用find(上界)-find(下界)的方法,即find(x)表示1-x范围内符合条件的个数。
首先看f(x),由于x的范围限制,f(x)最大到81,所以选择枚举y=f(x)。
举个例子,比如上界为45678,则其长度为5,mod是我们要枚举的,r的最终目的是0
所以进入搜索的条件是要找dfs(5-1,0,i,0)
前缀和为0,就是说我们要找到前缀和等于mod的情况,只要前缀和等于mod 并且余数为0就是符合的。
长度为le的总是由长度为le-1的求出,不停的添加,直到和大于等于mod为止,在判断r是否为0.
#include<iostream>
#include<cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int len,sum,num[11];
int d[11][82][82][82];
int dfs(int le,int s,int mod,int r,bool e)
{
if (mod>81||s>mod) return 0;
if (le==-1) return (s==mod&&r==0);
if (!e && d[le][s][mod][r]!=-1) return d[le][s][mod][r];
int res=0,x;
if (e) x=num[le];
else x=9;
for (int i=0;i<=x;i++)
res+=dfs(le-1,s+i,mod,(r*10+i)%mod,e&&i==x);
if (!e) d[le][s][mod][r]=res;
return res;
}
int find(int x)
{
len=sum=0;
while (x)
{
num[len++]=x%10;
x/=10;
}
int ans=0;
for(int i=1;i<=len*9;i++)
ans+=dfs(len-1,0,i,0,1);
return ans;
}
int main()
{
int n,k,a,b,C=1;
memset(d,-1,sizeof(d));
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
printf("Case %d: %d\n",C++,find(b)-find(a-1));
}
return 0;
}