Codeforces Beta Round #51 D 数位DP

来源:互联网 发布:手机淘宝不能改评价吗 编辑:程序博客网 时间:2024/05/22 04:24

题目链接

思路:
数位DP,维护三个量:
pos:当前处理到的位数
sta :状态压缩,保存该数数位上的数出现情况,只需要保存 2 ~ 9
mo : 之前处理过的数位上的数的最小公倍数。(因2…9的最小公倍数为2520,故可取模节省内存)

w[]:预处理每一位为1时对2520取模的余数。
然后记忆化搜索即可。

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int mod = 2520;ll dp[20][260][2600];int dig[20],w[20];int tot;ll dfs(ll pos,ll sta,ll mo,ll limit){    if(!limit && dp[pos][sta][mo] != -1) return dp[pos][sta][mo];    if(pos < 1){        bool flag = true;        for(int i=2 ;i<10 ;i++){            if(sta&(1<<(i-2))){                if(mo % i){                    flag = false;                    break;                }            }        }        if(flag) return 1;        return 0;    }    int end = limit?dig[pos]:9;    ll res = 0;    for(int i=0 ;i<=end ;i++){        ll _sta = sta;        if(i >= 2) _sta |= (1<<(i-2));        res += dfs(pos-1,_sta,(mo + i*w[pos])%mod,limit&&i==end);    }    if(!limit) dp[pos][sta][mo] = res;    return res;}ll solve(ll x){    tot = 0;    while(x){        dig[++tot] = x%10;        x /= 10;    }    return dfs(tot,0,0,1);}int main(){    memset(dp,-1,sizeof(dp));    w[1] = 1;    for(int i=2 ;i<20 ;i++){        w[i] = (w[i-1] * 10) % mod;    }    int T;    scanf("%d",&T);    while(T--){        ll l,r;        scanf("%I64d%I64d",&l,&r);        printf("%I64d\n",solve(r) - solve(l-1));    }    return 0;}
0 0
原创粉丝点击