正题
题目链接:https://ac.nowcoder.com/acm/contest/11179/E
题目大意
定义f(x)f(x)f(x)表示1x\frac{1}{x}x1的混循环节长度(如果没有循环节就是000),TTT组询问给出l,rl,rl,r求
∑i=lrf(i)\sum_{i=l}^rf(i)i=l∑rf(i)
1≤T≤100,1≤l≤r≤10151\leq T\leq 100,1\leq l\leq r\leq 10^{15}1≤T≤100,1≤l≤r≤1015
解题思路
设aia_iai表示iii位之后的余数,那么出现循环节当且仅当aia_iai出现重复。
ai=ai−1×10%n⇒ai=10i%na_i=a_{i-1}\times 10\% n\Rightarrow a_i=10^i\%nai=ai−1×10%n⇒ai=10i%n
那么出现循环节一定满足存在一个正整数kkk使得
ai×10k≡ai(modn)a_i\times 10^k\equiv a_i(mod\ n)ai×10k≡ai(mod n)
⇒10k≡1(modngcd(ai,n))\Rightarrow 10^k\equiv 1(mod\ \frac{n}{gcd(a_i,n)})⇒10k≡1(mod gcd(ai,n)n)
我们知道10k≡1(modn)10^k\equiv 1(mod\ n)10k≡1(mod n)有解当且仅当gcd(10,n)=1gcd(10,n)=1gcd(10,n)=1。
也就是说我们要找到第一个iii使得gcd(10,ngcd(ai,n))=1gcd(10,\frac{n}{gcd(a_i,n)})=1gcd(10,gcd(ai,n)n)=1。
而aia_iai每次乘十,所以相当于nnn每次在质因数中去掉一个222和555,直到和101010互质。
但是这样还没有结束,因为如果没有循环节就是000,而这里则会统计小数的长度,得减去这些情况,不难发现有循环节的话当且仅当存在某个10k%n=010^k\%n=010k%n=0,也就是说nnn只由222和555构成,暴力枚举这些数就好了。
时间复杂度:O(Tlog2nlog5n)O(T\log_2n\log_5 n)O(Tlog2nlog5n)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll P=998244353;
ll T,l,r;
int Ask(ll n){ll ans=n;for(ll i=1,pw=2;pw<=n;i++,pw=pw*2ll)ans=(ans+n/pw)%P;for(ll i=1,pw=5;pw<=n;i++,pw=pw*5ll)ans=(ans+n/pw)%P;for(ll i=1,pw=10;pw<=n;i++,pw=pw*10ll)ans=(ans-n/pw)%P;for(ll i=1,pw=1;pw<=n;i++,pw=pw*2ll)for(ll j=1,qw=1;pw*qw<=n;j++,qw=qw*5ll)(ans-=max(i,j))%=P;return (ans+P)%P;
}
signed main()
{scanf("%lld",&T);while(T--){scanf("%lld%lld",&l,&r);printf("%lld\n",(Ask(r)-Ask(l-1)+P)%P);}return 0;
}