题目链接
思路:显然暴力的做法是for i:1-r 看在[l,r]内有多少个数是是i的倍数。
for(int i=1;i<=r;i++){ ans[get(i)]+=r/i-(l-1)/i;//get()为获取i的第一个数码 }
怎么优化呢?
观察暴力的式子我们可以发现:r/i和(l-1)/i是两个除法的式子。显然是可以除法分块的。
这样就可以把正贡献和负贡献分开用除法分块计算。
统计答案的时候模拟一下即可。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 2e5 + 10; #define fi first #define se second #define pb push_back LL cnt[55],fac[13]; void add(int l,int r,int x,int y){ int xx=0,yy=0,g1=0,g2=0,R=r,L=l;//cout<<l<<' '<<r<<endl; while(l){ g1=l%10; l/=10; xx++; } while(r){ g2=r%10; r/=10; yy++; } if(xx==yy && g1==g2){ cnt[g1]+=1ll*y*x*(R-L+1); }else if(xx==yy && g1!=g2){ for(int i=g1+1;i<g2;i++){ cnt[i]+=1ll*y*x*fac[xx-1]; } cnt[g1]+=1ll*y*x*(1ll*(g1+1)*fac[xx-1]-L); cnt[g2]+=1ll*y*x*(R-1ll*g2*fac[yy-1]+1); }else{ for(int i=xx;i<yy-1;i++){ for(int j=1;j<=9;j++){ cnt[j]+=1ll*y*x*fac[i]; } } for(int i=g1+1;i<=9;i++){ cnt[i]+=1ll*y*x*fac[xx-1]; } for(int i=1;i<g2;i++){ cnt[i]+=1ll*y*x*fac[yy-1]; } cnt[g1]+=1ll*y*x*(1ll*(g1+1)*fac[xx-1]-L); cnt[g2]+=1ll*y*x*(R-1ll*g2*fac[yy-1]+1); } } int l,r; int main() { ios::sync_with_stdio(false); fac[0]=1; for(int i=1;i<=10;i++)fac[i]=fac[i-1]*10; cin>>l>>r; l--; for(int i=1,j;i<=r;i=j+1){ j=r/(r/i); add(i,j,r/i,1); } for(int i=1,j;i<=l;i=j+1){ j=l/(l/i); add(i,j,l/i,-1); } for(int i=1;i<=9;i++)cout<<cnt[i]<<'\n'; return 0; }