题目
Volodya是一个很皮的男♂孩。他认为一个能被它自己的每一位数上的数整除的数是很妙的。我们先忽略他的想法的正确性(如需证明请百度“神奇海螺”),只回答在l到r之间有多少个很妙的数字。
输入输出格式
输入:总共有t个询问:
第一行:t;
接下来t行:每行两个数l和r。
注意:请勿使用%lld读写长整型(虽然我也不知道为什么),请优先使用cin(或者是%I64d)。
输出:t行,每行为一个询问的答案。
Input
1
1 9
Output
9
Input
1
12 15
Output
2
解说
第一遍:这道题暴力简直太简单了,先暴力一遍试试。
结果70组数据跑了8个就TLE了。
那这种东西怎么优化?洛谷一搜,卧槽,黑题!!!
我怂了,真不是我怂,我一道黑题都没过过啊,无力承受这种恐怖!
看题解吧。
(还是选取我认为说的最清楚的)
等一下,它说这是数位DP模板题?!
哦,一种新的DP啊,那难怪我不会,那就学习到了啊!
个人能力限制,看完思路还是难以代码实现,所以照着仙贝的敲了一遍。一遍敲下来也算是理解了。
我A了一道黑题!
代码
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<cmath>
5 #include<algorithm>
6 #include<vector>
7 using namespace std;
8 typedef long long ll;
9 #define Mod 2520
10 int cur,a[Mod+3];
11 ll l,r,f[20][Mod+3][50];
12 vector<int> dim;
13 int gcd(int x,int y){return x%y?gcd(y,x%y):y;}
14 int getlcm(int x,int y){if(!y)return x;return x/gcd(x,y)*y;}
15 ll dfs(int x,int mode,int lcm,bool op){
16 if(!x) return mode%lcm==0?1:0;
17 if(!op&&f[x][mode][a[lcm]])return f[x][mode][a[lcm]];
18 int maxx=op?dim[x]:9;
19 ll ret=0;
20 for(int i=0;i<=maxx;i++)ret+=dfs(x-1,(mode*10+i)%Mod,getlcm(lcm,i),op&(i==maxx));
21 if(!op)f[x][mode][a[lcm]]=ret;
22 return ret;
23 }
24 ll solve(ll x){
25 dim.clear();
26 dim.push_back(-1);
27 ll t=x;
28 while(t) {
29 dim.push_back(t%10);
30 t/=10;
31 }
32 return dfs(dim.size()-1,0,1,1);
33 }
34 int main(){
35 for(int i=1;i<=Mod;i++)if(Mod%i==0)a[i]=++cur;
36 int t;
37 cin>>t;
38 while(t--){
39 cin>>l>>r;
40 cout<<solve(r)-solve(l-1)<<endl;
41 }
42 return 0;
43 }
幸甚至哉,歌以咏志。