2018上海大都会J题 Beautiful Numbers codeforces 55D Beautiful Numbers

链接:https://www.nowcoder.com/acm/contest/163/J
来源:牛客网
 

题目描述

NIBGNAUK is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by the sum of its digits.

We will not argue with this and just count the quantity of beautiful numbers from 1 to N.

输入描述:

The first line of the input is T(1≤ T ≤ 100), which stands for the number of test cases you need to solve.
Each test case contains a line with a positive integer N (1 ≤ N ≤ 1012).

输出描述:

For each test case, print the case number and the quantity of beautiful numbers in [1, N].

示例1

输入

复制

2
10
18

输出

复制

Case 1: 10
Case 2: 12

题意: 一个数是好数的条件是他取模它本身所有位的和为 0 也就是所有位和的倍数。

注意到这里的位数最多只有12 位 ,那么和最大是多少呢 12*9 =108 当然不可能达到108 ,如果我们知道了一个数的所有位 的和为num 那么要怎么判断是不是num的倍数呢,只需要让x%num就可以了,当然,这里枚举那是不可能的,所以就用数位dp来做。我们枚举1到108 让他作为mod ,那么直接dp就可以了。

代码: 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

ll dp[15][110][110][110];
int dig[15];

void init()
{
    memset(dp,-1,sizeof(dp));
}

ll dfs(int pos,int sum,int num,int mod,int lim)
{
    if(pos==0){
        if(sum==0&&num==0) return 1;
        return 0;
    }
    if(!lim&&dp[pos][sum][num][mod]!=-1) return dp[pos][sum][num][mod];
    ll res=0;
    int up=lim?dig[pos]:9;
    for(int i=0;i<=up;i++){
        res+=dfs(pos-1,(sum*10+i)%mod,num-i,mod,lim&&i==up);
    }
    if(!lim) dp[pos][sum][num][mod]=res;
    return res;
}

ll solve(ll x)
{
    int cnt=0;
    memset(dig,0,sizeof(dig));
    while(x){
        dig[++cnt]=x%10;
        x/=10;
    }
    ll ans=0;
    for(int i=1;i<=108;i++){ // 每个数的各位数 的总和绝对不会超过108=12*9
        ans+=dfs(cnt,0,i,i,1);
    }
    return ans;
}

int main()
{
    init();
    int kk=0;
    int T;
    scanf("%d",&T);
    ll n;
    while(T--)
    {
        scanf("%lld",&n);
        ll ans=solve(n);
        printf("Case %d: %lld\n",++kk,ans);
    }
    return 0;
}

做这个题的时候想到了以前做过的一个题 codeforces 55d,之前这个题给我的印象还是挺深刻的,做了老长时间,但是还是没做到家。

D. Beautiful numbers

time limit per test

4 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful numbers in given ranges.

Input

The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two natural numbers li and ri(1 ≤ li ≤ ri ≤ 9 ·1018).

Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).

Output

Output should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).

Examples

input

Copy

1
1 9

output

Copy

9

input

Copy

1
12 15

output

Copy

2

思路: x要是每一个非零位的倍数,1到9的最小公倍数为2520 那么我们就可以,取模2520.如果取模后的值是所有位的最小公倍数的倍数,那么x就一定是所有位的最小公倍数,mod是为了降低空间复杂度。

代码: 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

///ll dp[20][2525][2525]  这里我们本来应该开2520来表示所有位的lcm 但是注意到其实有好多位使我们用不到的。

int lcm(int a,int b)
{
    return a*b/__gcd(a,b);
}
int tot=0;
int inde[2520];
ll dp[20][2525][50];
int dig[20];

void init()
{
    for(int i=1;i<=2520;i++){
        if(2520%i==0){
            inde[i]=++tot;// 表示i是2520的因子。
        }
    }
    memset(dp,-1,sizeof(dp));
    ///cout<<"tot "<<tot<<endl;  注意到这里的tot 只有48,所以我可以把dp数组的第三维压缩到50
}

ll dfs(int pos,int sum,int lcmm,int lim)
{
    if(pos==0){
        if(sum%lcmm==0) return 1;
        return 0;
    }
    if(!lim&&dp[pos][sum][inde[lcmm]]!=-1) return dp[pos][sum][inde[lcmm]];
    int up=lim?dig[pos]:9;
    ll res=0;
    for(int i=0;i<=up;i++){
        int tmplcm=1;
        if(i==0) tmplcm=lcmm;
        else tmplcm=lcm(lcmm,i);
        res+=dfs(pos-1,(sum*10+i)%2520,tmplcm,lim&&i==up);
    }
    if(!lim) dp[pos][sum][inde[lcmm]]=res;
    return res;
}

ll solve(ll x)
{
    memset(dig,0,sizeof(dig));
    int cnt=0;
    while(x)
    {
        dig[++cnt]=x%10;
        x/=10;
    }
    ll ans=0;
    ans+=dfs(cnt,0,1,1);
    return ans;
}

/*
int main()
{
    ll ans=1;
    for(ll i=2;i<=9;i++){
        ans=lcm(ans,i);
    }
    cout<<ans<<endl;
    return 0;
}
*/

int main()
{
    init();
    ll l,r;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld %lld",&l,&r);
        ll ans=solve(r)-solve(l-1);
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/81479292