2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J.Beautiful Numbers

题目:
给你一个数,如果这个数能被这个数的各个数位上的数的和整除,那么这个数是beautiful number. 给你一个n, 求从1到n有多少个漂亮数。

输入:
样例T
每行一个n

输出:
小于n的beautiful number 的个数(1 ≤ N ≤ 1e12).

一道数位dp题,感觉数位dp,一般sum值很大,数组肯定开不下,所以要尽可能的压缩sum的值,这道题假设n有len位,所以能整除n的数肯定在[1,9*len]之间,所以sum只需要开到9*12,对区间内的每一个数作为mod,跑一遍dfs,如果结束的时候ans数位之和等于mod,就是漂亮数。dfs里的sum和ans要用int不然会TLE。。。

#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
ll dp[50][205][205];//dp[数位][数值][各数位数之和]
ll dis[505];
int mod;
ll dfs(int pos,int sum,int ans,bool flag){//pos是数位,sum是数值,ans是数位数之和,sum,ans用int
    if(pos==0) return ans==mod&&!sum;
    if(!flag&&dp[pos][sum][ans]!=-1) return dp[pos][sum][ans];
    ll res=0;
    int up=flag?dis[pos]:9;
    for(int i=0;i<=up;i++){
        int ssum=(sum*10+i)%mod;//int
        int aans=ans+i;//int
        if(aans>mod) break;
        res+=dfs(pos-1,ssum,aans,flag&&i==up);
    }
    if(!flag)
        dp[pos][sum][ans]=res;
    return res;
}
ll solve(ll n){
    int len=0;
    while(n){
        dis[++len]=n%10;
        n/=10;
    }
    ll res=0;
    for(int i=1;i<=9*len;i++){
        mod=i;
        memset(dp,-1,sizeof(dp));
        res+=dfs(len,0,0,true);
    }
    return res;
}
ll cnt=0;
int c=1;
int main(){
    int T;
    cin>>T;
    int i,j;
    while(T--){
        ll n;
        scanf("%lld",&n);
        printf("Case %d: %lld\n",c++,solve(n));
    }
    return 0;
}

你可能感兴趣的:(2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J.Beautiful Numbers)