[AHOI2009]同类分布

题目描述

给出两个数a,b,求出[a,b]中各位数字之和能整除原数的数的个数。

输入格式

一行,两个整数a和b

输出格式

一个整数,表示答案

输入输出样例

输入 #1
10 19
输出 #1
3

说明/提示

对于所有的数据,1≤a≤b≤10181 ≤ a ≤ b ≤ 10^{18}1ab1018

【解题思路】

本题记录前面的数字的和,同时还要知道最后产生的数字是否整除和。

• 记录各位数字的和比较容易,共9*18个状态。关键是如何知道已经产生 的数位构成的数字是否整除最后的总和,比较麻烦。考虑求模,整除的 模数为0,可以记录已经产生的数字的模数,但是又不知道最后的数字总 和是多少,这个模数怎么记录?可以这样定义:

• F[20][200][200][200]->f[i][sum][m][mod]表示到第i位,前面数字总和为sum ,%mod的余数为m,然后枚举mod即可计算。

• 这样可以解决问题,但是计算内存发现:需要1G的内存,只好想办法压 缩空间,因为mod是要在程序中枚举的,所以不必记录这一维状态,这 样空间就足够了

• F[20][200][200]->f[i][sum][m]表示到第i位,前面数字总和为sum,%mod的 余数为m,然后枚举mod即可计算

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 long long dp[20][201][201],bit[21],a,b,MOD;
 6 long long dfs(int p,int sum,int mod,int limt){//数位dp模板,被我改了点小地方
 7     if(p==0){
 8     if(mod==0&&sum==MOD)
 9         return 1;
10         else return 0;}
11     int up=limt?bit[p]:9;
12     if(!limt&&dp[p][sum][mod]!=-1)return dp[p][sum][mod];
13     long long ret=0;
14     for(int i=0;i<=up;++i)
15         ret+=dfs(p-1,sum+i,(mod*10+i)%MOD,limt&&up==i);
16     if(!limt)
17         dp[p][sum][mod]=ret;return ret;
18 }
19 long long solve(long long n){
20     int len=0,mod=0;
21     while(n){mod+=n%10;
22     bit[++len]=n%10;n/=10;}
23     long long ret=0;
24     for(MOD=1;MOD<=len*9;MOD++){//枚举
25         memset(dp,-1,sizeof(dp)); //这里必须清,当然,清成什么取决于你
26         ret+=dfs(len,0,0,1);
27     }
28     return ret;
29 }
30 int main(){
31     scanf("%lld%lld",&a,&b);
32     printf("%lld",solve(b)-solve(a-1));
33     return 0;
34 }

 

posted @ 2019-07-25 21:37  GTR_PaulFrank  阅读(185)  评论(0编辑  收藏  举报