思路按照训练指南上说的的递推,table[i][j][k]表示i位数各位数字和对给定数取模为j,数字本身对给定数取模为k的数字个数,最后的统计细节需要注意,要从高位到低位统计,个位要单算。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
using std::endl;
const int MAXN(82);
int table[11][MAXN+10][MAXN+10];
int arr[11][MAXN+10][MAXN+10];
int count(int sour, int K)
{
if(sour < 10)
return sour/K;
int weight = 1, mxb = 0;
while(sour/weight >= 10)
{
weight *= 10;
++mxb;
}
int b1 = 0, b2 = 0;
int ret = 0;
for(int i = mxb; i > 0; --i)
{
int temp = sour/weight;
for(int j = 0; j < temp; ++j)
ret += table[i-1][((K-j-b1)%K+K)%K][((K-j*weight-b2)%K+K)%K];
b1 += temp;
b2 += temp*weight;
sour -= temp*weight;
weight /= 10;
}
for(int i = 0; i <= sour; ++i)
if(((K-i-b1)%K+K)%K == 0 && ((K-i-b2)%K+K)%K == 0)
++ret;
--ret;
return ret;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int A, B, K;
scanf("%d%d%d", &A, &B, &K);
if(K > MAXN)
{
printf("0\n");
continue;
}
memset(table, 0, sizeof(table));
int size = -1, tb = B;;
while(tb)
{
++size;
tb /= 10;
}
for(int i = 0; i <= 9; ++i)
table[0][i%K][i%K] += 1;
int weight = 1;
for(int i = 1; i < size; ++i)
{
weight *= 10;
for(int k1 = 0; k1 < K; ++k1)
for(int k2 = 0; k2 < K; ++k2)
for(int j = 0; j <= 9; ++j)
table[i][(k1+j)%K][((j*weight+k2)%K+K)%K] += table[i-1][k1][k2];
}
printf("%d\n", count(B, K)-count(A-1, K));
}
return 0;
}
有一个比较类似的问题求从0到n所有数中k( 0<=k<= 9)出现的次数,从0到11,1一共出现了4次,统计的方法为分别对每一位上k出现的次数统计,记得编程之美上有这道问题,当k=0时要注意把类似00,01,02,...,000,001......中0的个数减去,扩展后可以都到不同进制下,不同数字出现的个数
LL count(LL sour, LL goal, LL BASE) //原数, 数字k, 进制
{
if(sour < 0)
return 0LL;
LL weight = 1LL, ts = 0LL;
LL ret = 0LL;
while(sour)
{
LL t1 = sour%BASE, t2 = sour/BASE;
if(t1 > goal)
++t2;
else
if(t1 == goal)
ret += (ts+1);
ret += weight*t2;
if(!goal)
ret -= weight;
ts += t1*weight;
sour /= BASE;
weight *= BASE;
}
if(!goal)
++ret;
return ret;
}