标签:hid 多次 出现 eof pen 个数 大小 之间 msu
对于一个数,如果他能被任何一位上的数整除,那么他就是beautiful number,有t组询问求[l,r]的beautiful number。
1<=li?<=ri?<=9⋅1018
看到没有一点思路,甚至想到上次做的数位DP想把[0,9]都开出一维,但是不仅空间过不去,而且不知道咋处理这个数没出现。
那么就去借鉴题解,lcm(???)
整除每一位就是整除出现过的数的lcm!!!
[1..9]的最小公倍数2520,出现过的数的lcm一定是2520的因数,所以只用判断x%2520是不是lcm的倍数即可,因为%相当于减法,那么-2520就是减多次lcm,就相当于%lcm只是最后的数在[0,2520)之间。
所以f[s][sum][lcm]表示当前第s位,%2520为sum,出现过的数的lcm
但是还是空间爆了,但是还是因为lcm是2520的因数,所以第三维只用开因数个数大小即可,同一个数组映射。
#include<bits/stdc++.h> using namespace std; #define ll long long const int mod=2520; int t,cnt,mp[2530]; ll l,r; ll f[20][2530][50]; int len,num[20]; int gcd(int a,int b){ return !b ? a : gcd(b,a%b); } ll dfs(int s,int sum,int lcm,bool lim){ if(!s) return !(sum%lcm); if(!lim&&f[s][sum][mp[lcm]]!=-1) return f[s][sum][mp[lcm]]; int mx= lim ? num[s] : 9; ll ret=0; for(int i=0;i<=mx;i++) ret+=dfs(s-1,(sum*10+i)%mod,!i ? lcm : lcm/gcd(lcm,i)*i,lim&&i==mx); if(!lim) f[s][sum][mp[lcm]]=ret; return ret; } ll cx(ll x){ len=0; while(x){ num[++len]=x%10; x/=10; } return dfs(len,0,1,true); } int main(){ for(int i=1;i<=mod;i++) if(!(mod%i)) mp[i]=++cnt; scanf("%d",&t); memset(f,-1,sizeof(f)); while(t--){ scanf("%I64d%I64d",&l,&r); printf("%I64d\n",cx(r)-cx(l-1)); } }
标签:hid 多次 出现 eof pen 个数 大小 之间 msu
原文地址:https://www.cnblogs.com/sto324/p/11402749.html