题目:
Now, we have a function f(x):
int f ( int x ) {
if ( x == 0 ) return 0;
return f ( x / 10 ) + x % 10;
}
For a given interval [A, B] (1 <= A <= B <= 10^9), calculate how many integer x that mod f(x) equal to 0.
分析:
题意就是求[A,B]区间内能被自己各个数位的数字之和整除的数的个数
(1)打表:
由于范围不是特别大,可以每隔100000个数打一个表,最多开1e4的数组,时间最多1e5 * 50 * 10
(2)数位dp
考虑dp怎样定义状态,由于数位之和会变化,也就是模数f(x)不确定,也就定义不了状态,因为a % x = a % kx % x,所以我们可以确定每一次的模数为[1,81]的最小公倍数,但这个数太大,开不了dp数组,只有考虑枚举模数,也就是每次确定它的数位之和
HDU---3709(类似的处理方法)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int t,l,r,dit[15];
int dp[15][82][82][82];
int dfs(int pos,int sum,int mod,int MOD,int limit){
if(pos < 0) return mod == MOD && sum == 0 ;
if(mod > MOD) return 0;
if(!limit && ~dp[pos][mod][MOD][sum]) return dp[pos][mod][MOD][sum];
int up = limit ? dit[pos] : 9,num = 0;
for(int i = 0;i <= up; ++i){
num += dfs(pos-1,(sum*10+i)%MOD,mod+i,MOD,limit && dit[pos]==i);
}
if(!limit) dp[pos][mod][MOD][sum] = num;
return num;
}
int solve(int x){
int len = 0;
while(x){
dit[len++] = x % 10;
x /= 10;
}
int res = 0;
for(int i = 1;i <= 81; ++i) res += dfs(len-1,0,0,i,1);
return res;
}
int main(){
memset(dp,-1,sizeof(dp));
cin >> t;
for(int Case = 1;Case <= t; ++Case){
cin >> l >> r;
printf("Case %d: %d\n",Case,solve(r) - solve(l-1));
}
return 0;
}