Lightoj 1068(数位DP)

求一段区间中被k整除,各个位数相加之和被k整除的数的个数。

这不是重点,重点是k太大了,最大值有10000,所以不能直接开那么大的数组。

仔细分析一下可以发现,由于数最大是2的31次方(2147483648),所以当k>90时,直接输出0即可。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL  long long
#define maxn 30
LL  dp[maxn][100][100];
LL  digit[maxn];
LL  n,m,K;
LL dfs(int len,LL pre,LL before,bool fp)
{
    if(!len)
    {
       return pre==0&&before==0;
    }
    if(!fp && dp[len][pre][before] != -1)
        return dp[len][pre][before];
    LL   ret = 0 ;
    LL   fpmax = fp ? digit[len] : 9;
    for(int i=0;i<=fpmax;i++)
    {
        ret += dfs(len-1,(pre*10+i)%K,(before+i)%K,fp && i == fpmax);
    }
    if(!fp)
        dp[len][pre][before] = ret;
    return ret;
}

LL f(LL n)
{
    int len = 0;
    while(n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    return dfs(len,0,0,true);
}

void init()
{
    memset(dp,-1,sizeof(dp));
}
int main()
{
    //freopen("test.txt","r",stdin);
  // cout<< ((LL)1<<31)<<endl;
      int t;
     scanf("%d",&t);
     int Case=0;
     while(t--)
     {
          scanf("%d%d%d",&n,&m,&K);
          if(K>90)
          {
              printf("Case %d: 0
",++Case);
              continue;
          }
          init();
            printf("Case %d: %lld
",++Case,f(m)-f(n-1));
     }
    return 0;
}
原文地址:https://www.cnblogs.com/xianbin7/p/4759532.html