Lightoj1068——Investigation(数位dp)

来源:互联网 发布:淘宝店铺保证金怎么交 编辑:程序博客网 时间:2024/06/18 15:53

题面

题意

给出n,m,k,求出n到m间有几个数的数字和与整个数都是k的倍数

方法

虽然k<10000,然而因为n,m小于2^31,数字和最大也就八十几,故大于85的直接输出0.
用前缀和维护一下,要求n到m,只需要求0~m - 0~n-1 即可.
dp时只需记录当前长度,数字和对k取模的结果和数对k取模的结果.

代码

#include<bits/stdc++.h>#define ll long longusing namespace std;ll T,TT,n,m,k,dp[20][100][100],num[20],ten[]={1,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000};//³¤¶È,Êý×ÖºÍÈ¡Ä£Óë×ÜÊýÈ¡Ä£ll dfs(ll len,bool lim,ll szh,ll mod){    if(!len)    {        if(!szh&&!mod) return 1;        return 0;    }    if(!lim&&dp[len][szh][mod]!=-1) return dp[len][szh][mod];    ll mx=9,i,j,res=0;    if(lim) mx=num[len];    for(i=0;i<=mx;i++)    {        res+=dfs(len-1,lim&&i==mx,(k+szh-i)%k,(k+mod-i*ten[len]%k)%k);    }    if(!lim) dp[len][szh][mod]=res;    return res;}ll ys(ll u){    ll i,j;    i=0;    while(u)    {        i++;        num[i]=u%10;        u/=10;    }//  for(j=1;j<=i;j++) cout<<num[j]<<" ";//  cout<<endl;    return dfs(i,1,0,0);}int main(){    ll i,j;    cin>>T;    TT=T;    while(T--)    {        memset(dp,-1,sizeof(dp));        scanf("%lld%lld%lld",&n,&m,&k);        printf("Case %lld: ",TT-T);        if(k>=85)        {            printf("0\n");            continue;        }        printf("%lld\n",ys(m)-ys(n-1));    }}
原创粉丝点击