B

B - Investigating Div-Sum Property

UVA - 11361

题目描述:

例题6 数字和与倍数

​ 给定正整数a,b,k 你的任务是在所有满足a<=n<=b的整数n中,统计有多少个满足n自身是k的倍数,且n的各个数字(十进制)之和也是k的倍数?比如当k=7时,322满足条件,因为322和3+2+2都是7的整数倍。当a=1,b=1000,k=4时,有64个整数条件。

输入格式:

输入第一行为测试数据组数T(T<100)。以下T行每行3个整数a,b,k(1<=a<=b<=231, 1<=k<=1000)

输出格式:

对于每组数据,输出满足条件整数的个数

输入数据:

3

1 20 1

1 20 2

1 1000 4

输出数据:

20

5

64

思路:

不难想到用f(n)来表示 0~n中满足条件的个数,那么答案就是 f(b)f(a1)f(b)-f(a-1)

可以用加法原理

比如3212可以表示为

0***

1***

2***

30**

31**

320*

3210

3211

3212

​ *代表该数字为0~9中的其中一个

​ 用 f(d,m1,m2)f(d,m1,m2)来表示d个数字,十进制数位之和取余k等于m1,值取余k等于m2。

那么 $ f (d+1,m1,m2)=sum_{x=0}^{9} f ( d, (m1-x)%k,(m2-10^d)%k)$

当然 f(3,0,0)就值0~999中满足条件的个数

然后模拟将数字分解为上述情况,记下每种情况的前缀值和十进制位数的前缀和,计算出该情况下满足条件的个数就好了

举个例子:

0*** 用f(3,0,0)

1*** 用f(3,-1+k%k,-1000%k)

下面的就不列举了

注意int行十进制位数之和最大位9*9+1=100 所以不可能被大于100的k取余,所以当k>100的时候只有0符合条件

#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#define mset(a,b)   memset(a,b,sizeof(a))
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=10000;
const int branch=26;
const int inf=0x3f3f3f3f;
const int MOD=1e6+7;
int k;//取余k
int f[12][105][105];
int get_mod(int n,int mod);
void init()
{
    mset(f,0);//f[d][m1][m2]  要求 d>=1且 m1
    f[0][0][0]=1;//初始条件
    int ppw=1;
    for(int i=1;i<=9;++i)
    {
        for(int m1=0;m1<k;m1++)
        {
            for(int m2=0;m2<k;++m2)
            {
                int sum=0;
                for(int x=0;x<=9;++x)//枚举第i位数字
                {
                    sum+=f[i-1][get_mod(m1-x,k)][get_mod(m2-x*ppw,k)];
                }
                f[i][m1][m2]=sum;
            }
        }
        //记录 10^(i-1)
        ppw*=10;
    }
}
int get_mod(int n,int mod)
{
    return (n%mod+mod)%mod;
}
int solve(int num)//求0~num中有多少个数满足 取余k
{
   if(num==0)
     return 1;
   int ans=0;
   int top=0,pos[10];
   int nn=num;
   while(nn)
   {
       pos[top++]=nn%10;
       nn/=10;
   }
   int sum=0;//记录前缀的值
   int ppw=1;//记录权值
   int ss=0;//记录前缀的市值仅为之和
   for(int i=0;i<top-1;++i)
    ppw*=10;
   for(int i=top-1;i>=0;--i)
   {
       for(int j=0;j<pos[i];++j)
       {
           ans+=f[i][get_mod(-1*ss-j,k)][get_mod(-1*sum-ppw*j,k)];//组合数学加法原理
       }
       sum+=ppw*pos[i];
       ss+=pos[i];
       ppw/=10;
   }
   ans+=f[0][get_mod(-ss,k)][get_mod(-sum,k)];
   return ans;
}
int main()
{
    int t,a,b,ans;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&a,&b,&k);
        if(k>100)
        {
            printf("0
");
            continue;
        }
        init();//根据k 算出   0~9位数都有多少个
        ans=solve(b)-solve(a-1);
        printf("%d
",ans);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/dchnzlh/p/10427282.html