題意:
基本是看了大白上的思路,然後還參考了http://blog.csdn.net/lenleaves/article/details/9104417
統計大於等於a,小於等於b,每一位之和可以被k整除,且本身也能被k整除的數的數量。
用f(d,m1,m2)表示剩餘d個數字,這d個數字之和模k爲m1,這d個數字組成的整數倍k整除之後餘m2, 這樣的數字的數量,
求a與b之間這樣數字的數量,我們轉化問題爲前綴和只差即 sum(b)-sum(a-1) (具體求解過程的不同,此處可能會有小出入)。
狀態方程 訓練指南上面有一個小錯誤。
正確的狀態方程應爲
f(d,m1,m2)=sum{ f( d-1,(m1-x) mod k,(m2-x*10^(d-1)) mod k ) |x=0,1,2.......9}
注意當我們將星號限制在後面三位的時候,我第四位的枚舉範圍,應在原本第四位的範圍之內。而之後的枚舉過程中,由於第四位小於原本的第四位,所以低位可以從0枚舉到9
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int a,b,k;
int dp[15][110][110];
int pw[11]={1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
int dfs(int d,int m1,int m2) {
if(d == 0)
return (m1 == 0 && m2 == 0) ? 1 : 0;
if(dp[d][m1][m2] >= 0)
return dp[d][m1][m2];
dp[d][m1][m2]=0;
for(int i = 0; i < 10; i++)
dp[d][m1][m2] += dfs(d - 1, ((m1 - i) % k + k) % k, ((m2 - i * pw[d-1]) % k + k) % k);
return dp[d][m1][m2];
}
int func(int n) {
int d = 0, m1 = 0, m2 = 0, a[15];
if(n ==0)
a[d++] = 0;
while(n != 0) {
a[d] = n % 10;
n /= 10;
d++;
}
int ans=0;
for(int i = d - 1; i >= 0; i--) {
if(i!=0)
for(int j=0;j<a[i];j++) {
ans += dfs(i,(k-(m1+j)%k)%k,(k-(m2+pw[i]*j)%k)%k);
}
else
for(int j = 0; j <=a[i]; j++) {
ans+=dfs(i,(k-(m1+j)%k)%k,(k-(m2+pw[i]*j)%k)%k);
}
m1 += a[i];
m2 += pw[i] * a[i];
}
return ans;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &a, &b, &k);
if(k > 85)
printf("0\n");
else {
memset(dp,-1,sizeof(dp));
printf("%d\n",func(b)-func(a-1));
}
}
return 0;
}