CodeForces 55D 数位DP

来源:互联网 发布:战国立志传姬武将数据 编辑:程序博客网 时间:2024/06/05 17:40

点击打开链接

题意:求区间内的数字是每一位的倍数的数的数量

思路:加的状态是当前取余2520的余数,因为2520是1到9的最小公倍数,然后还有一个状态就是1到9都有哪些数出现了,可以用状态压缩来完成,然后最后就判断余数和出现的所有1到9的数是不是都取余为0即可

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const ll INF=0x3f3f3f3f3f3f3f3fll;const int maxn=5010;const int mod=2520;int dig[30],f[20];ll dp[20][2530][260];bool judge(int sum,int num){    for(int i=2;i<=9;i++){        if(sum>>(i-2)&1){            if(num%i!=0) return 0;        }    }    return 1;}ll dfs(int pos,int lim,int num,int sum){//num为余数,sum为状态压缩    if(pos<0) return judge(sum,num);    if(!lim&&dp[pos][num][sum]!=-1) return dp[pos][num][sum];    int las=lim?dig[pos]:9;    ll ret=0;    for(int i=0;i<=las;i++){        int tmp=sum;        if(i>=2){            if(sum>>(i-2)&1) tmp=sum;            else tmp+=(1<<(i-2));        }        ret+=dfs(pos-1,lim&&(i==las),(num*10+i)%mod,tmp);    }    if(!lim) dp[pos][num][sum]=ret;    return ret;}ll slove(ll n){    if(n==0) return 1;    int len=0;    while(n){        dig[len++]=n%10;        n/=10;    }    return dfs(len-1,1,0,0);}int main(){    memset(dp,-1,sizeof(dp));    int T,cas=1;    ll n,m;//    cout<<slove(9)<<"=="<<endl;    while(scanf("%d",&T)!=-1){        while(T--){            scanf("%I64d%I64d",&n,&m);            printf("%I64d\n",slove(m)-slove(n-1));        }    }    return 0;}

0 0
原创粉丝点击