洛谷 CF55D Beautiful numbers 解題報告
阿新 • • 發佈:2019-02-10
main can dfs clas ron gcd 解題報告 const return
CF55D Beautiful numbers
題意
\(t(\le 10)\)次詢問區間\([l,r](1\le l\le r\le 9\times 10^{18})\)中能被每一位上數整除的數的個數,0算可以整除任何數。
最開始寫了個假做法,既沒算0復雜度也是假的
最開始把每個模數都壓進去了,後來發現只壓2520就可以了
然後前兩位壓前\(i\)位與\(\bmod 2520\)的結果,第三位最開始壓了每個數字出現集合,這樣就很屑。
可以直接壓數字集合的最小公倍數,僅有不到50個取值,做一個Hash存一下就可以了。
寫起來也簡單
Code:
#include <cstdio> #include <cstring> #define ll long long const int p=2520; ll dp[20][p][50]; int yuy[p],bit[20],po[20],cnt; int gcd(int x,int y){return y?gcd(y,x%y):x;} int LCM(int x,int y){return y?x*y/gcd(x,y):x;} ll dfs(int pos,int res,int lcm,int lim) { if(!pos) return res%lcm==0; if(!lim&&~dp[pos][res][yuy[lcm]]) return dp[pos][res][yuy[lcm]]; ll ret=0; for(int i=0,up=lim?bit[pos]:9;i<=up;i++) ret+=dfs(pos-1,(res+po[pos-1]*i)%p,LCM(lcm,i),lim&&i==up); return lim?ret:dp[pos][res][yuy[lcm]]=ret; } ll cal(ll x) { int len=0;while(x) bit[++len]=x%10,x/=10; return dfs(len,0,1,1); } int main() { memset(dp,-1,sizeof dp); int T;scanf("%d",&T); for(int i=1;i<p;i++) if(p%i==0) yuy[i]=++cnt; po[0]=1;for(int i=1;i<=18;i++) po[i]=po[i-1]*10%p; while(T--) { ll l,r;scanf("%lld%lld",&l,&r); printf("%lld\n",cal(r)-cal(l-1)); } return 0; }
2019.2.10
洛谷 CF55D Beautiful numbers 解題報告