The 2018 ACM-ICPC上海大都会赛 J Beautiful Numbers (数位DP)

Posted xiuwenli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The 2018 ACM-ICPC上海大都会赛 J Beautiful Numbers (数位DP)相关的知识,希望对你有一定的参考价值。

题意:求小于等于N且能被自己所有位上数之和整除的数的个数。

分析:裸的数位dp。用一个三位数组dp[i][j][k]记录:第i位,之前数位之和为j,对某个mod余数为k的状态下满足条件的个数。这里mod的值就是小于等于N的数中,所有可能出现的数位之和。所以solve函数中需要对dfs函数做一个循环,上限是9*pos(数位之和不会超过9*pos)。

还有需要注意的是,在递归的时候可以通过判断当前数位之和sum是否超过mod,超过的话肯定在这个状态下没有满足条件的数,以此剪枝优化。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
const int INF =0x3f3f3f3f;
typedef long long LL;
int a[20];
LL dp[13][105][150];        //dp[i][j][k]记录 第i位,前面数位之和为j,对某个mod的余数是k的状态下满足条件的个数
int mod;

LL dfs(int pos,int sum,int remain,bool limit){
    if(pos==-1) return (sum==mod && !remain);
    if(dp[pos][sum][remain]!=-1 && !limit) return dp[pos][sum][remain];
    int up = limit? a[pos]:9;
    LL res=0;
    for(int i=0;i<=up;++i){
        if(i+sum>mod) break;            //剪枝
        res+=dfs(pos-1,sum+i,(remain*10+i)%mod,limit && i==a[pos]);
    }
    if(!limit) dp[pos][sum][remain] = res;
    return res;
}

LL solve(LL N)
{
    int pos=0;
    LL x=N;
    while(x){
        a[pos++]=x%10;
        x/=10;
    }
    LL res=0;
    for(int i=1;i<=9*pos;++i){
        mod=i;                          
        memset(dp,-1,sizeof(dp));       //这里的dp数组记录的只是针对一种模数的状态,所以每次都要清空
        res+=dfs(pos-1,0,0,true);
    }
    return res;
}

int main(){
    int T,M,num,t,x;
    LL N;
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    while(scanf("%lld",&N)==1){
        printf("%lld
",solve(N));
    }
    return 0;
}

 

以上是关于The 2018 ACM-ICPC上海大都会赛 J Beautiful Numbers (数位DP)的主要内容,如果未能解决你的问题,请参考以下文章

2018 ACM 国际大学生程序设计竞赛上海大都会赛

2018ACM-ICPC南京区域赛M---Mediocre String ProblemexKMPManacher

The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online J Press the Button

2019 ACM-ICPC 上海网络赛 B. Light bulbs (差分)

2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛-B-Perfect Numbers(完数)

2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛-K-Matrix Multiplication(矩阵乘法)