[数论记录]AT3884 [ARC090D] Number of Digits
command_block · · 个人记录
题意 : 记
给出
-
1\leq l\leq r -
\sum\limits_{i=l}^rf(i)=S
答案对
枚举
若
故方案数为 :
大力求因数,复杂度为
- Case 2 :
f(r)-f(l)=1
枚举
为了与 Case 1 区分,这里要求
化式子 :
注意到当确定
由
解得
还要考虑
注意到当
其他的部分为
也只需统计因数。
- Case 3 :
f(r)-f(l)>1
枚举
由于此时我们跨越了至少一整段,
设区间中
此时仍然有
计算出中间整段的
问题转化为 : 给出不定方程
记
用
将范围不等式的四个边界分别代入,即可得知方案数。
这部分的复杂度为
细节真多……
#include<algorithm>
#include<cstdio>
#define ll long long
using namespace std;
const int mod=1000000007;
ll powM(ll a,ll t){
ll ret=1;t%=(mod-1);
while(t){
if (t&1)ret=ret*a%mod;
a=a*a%mod;t>>=1;
}return ret;
}
void exgcd(ll a,ll b,ll &x,ll &y){
if (b==0){x=1;y=0;return ;}
exgcd(b,a%b,y,x);y-=(a/b)*x;
}
int gcd(int a,int b)
{return !b ? a : gcd(b,a%b);}
ll n,lim[15];
int main()
{
scanf("%lld",&n);
lim[1]=9;for (int i=2;i<=13;i++)lim[i]=lim[i-1]*10;
ll ans=0;
for (int i=1;1ll*i*i<=n;i++)
if (n%i==0){
ll d=i;
if (d>12)ans--;
if (d>12||n/d<=lim[d])
ans=(ans+9*powM(10,d-1)-n/d+1)%mod;
if (1ll*i*i==n)continue;
d=n/i;
if (d>12)ans--;
if (d>12||n/d<=lim[d])
ans=(ans+9*powM(10,d-1)-n/d+1)%mod;
}
for (int k=1;k<=12;k++){
ll l=max(n/(k+1)+1,(n-lim[k+1]*(k+1)+k-1)/k+lim[k+1])
,r=min((n-1)/k,(n-lim[k]*k)/(k+1)+lim[k]);
ans=(ans+((r>=l) ? r-l+1 : 0))%mod;
}ans=(ans+n/13)%mod;
for (int kl=1;kl<=12;kl++)
for (int kr=kl+2;kr<=12;kr++){
ll s=n;
for (int j=kl+1;j<kr;j++)s-=lim[j]*j;
int d=gcd(kl,kr);
if (s%d||s<=0)continue;
s/=d;int a=kl/d,b=kr/d;
ll limx=lim[kl],limy=lim[kr],x,y,xl,xr;
exgcd(a,b,x,y);x*=s;y*=s;
x=(x%b+b)%b;xl=!x ? b : x;
y=(y%a+a)%a;if (!y)y=a;xr=(s-b*y)/a;
x+=limx/b*b+b;while (x>limx)x-=b;xr=min(xr,x);
y+=limy/a*a+a;while (y>limy)y-=a;xl=max(xl,(s-b*y)/a);
if (xl<=xr)ans+=(xr-xl)/b+1;
}
printf("%lld",(ans+mod)%mod);
return 0;
}