「题解」最简真分数
作者:互联网
本文将同步发布于:
题目
题意简述
给定两个最简真分数和正整数 \(\frac{a}{b},\frac{c}{d},n\),求有多少个最简真分数 \(\frac{e}{f}\) 满足 \(f\in[1,n]\) 且 \(\frac{a}{b}\leq\frac{e}{f}\leq\frac{c}{d}\)。
\(1\leq n\leq 10^{10}\)。
题解
限制转化
我们考虑枚举 \(f\),那么 \(e\) 需要满足的条件为 \(\left\lceil\frac{af}{b}\right\rceil\leq e\leq\left\lfloor\frac{cf}{d}\right\rfloor\) 且 \(\gcd(e,f)=1\)。
不妨同统一形式,把 \(\left\lceil\frac{af}{b}\right\rceil\) 转化为 \(\left\lfloor\frac{af+b-1}{b}\right\rfloor\)。
我们要求解的答案即为:
\[\sum_{f=1}\sum^f_{e=1}\epsilon\left(\gcd(e,f)\right)\left[\left\lfloor\frac{af+b-1}{b}\right\rfloor\leq e\leq\left\lfloor\frac{cf}{d}\right\rfloor\right] \]\[\sum_{f=1}\sum^{\left\lfloor\frac{xf+y}{z}\right\rfloor}_{e=1}\epsilon\left(\gcd(e,f)\right) \]\[\sum^n_{d=1}\mu(d)\sum_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\left\lfloor\frac{xdi+y}{dz}\right\rfloor \]这个显然可以用数论分块+杜教筛+类欧几里得算法做。
参考程序
#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
bool st;
const int mod=998244353;
struct modInt{
int x;
inline modInt(reg int x=0):x(x){
//assert(0<=x&&x<mod);
return;
}
inline modInt operator+(const modInt& a)const{
reg int sum=x+a.x;
return sum>=mod?sum-mod:sum;
}
inline modInt operator-(const modInt& a)const{
reg int sum=x-a.x;
return sum<0?sum+mod:sum;
}
inline modInt operator-(void)const{
return modInt(0)-*this;
}
inline modInt operator*(const modInt& a)const{
return 1ll*x*a.x%mod;
}
inline void operator+=(const modInt& a){
x+=a.x;
if(x>=mod) x-=mod;
return;
}
inline void operator-=(const modInt& a){
x-=a.x;
if(x<0) x+=mod;
return;
}
inline void operator*=(const modInt& a){
x=1ll*x*a.x%mod;
return;
}
};
inline modInt fpow(modInt x,reg int exp){
modInt res=1;
while(exp){
if(exp&1)
res*=x;
x*=x,exp>>=1;
}
return res;
}
const modInt inv2=fpow(2,mod-2);
ll n;
int a,b,c,d;
const int MAXS=1e7+5;
const int S=1e7;
bool vis[MAXS];
int tot,prime[MAXS];
modInt mu[MAXS];
modInt Smu[MAXS];
inline void Init(reg int n){
mu[1]=1;
for(reg int i=2;i<=n;++i){
if(!vis[i])
prime[++tot]=i,mu[i]=-modInt(1);
for(reg int j=1;j<=tot&&i*prime[j]<=n;++j){
vis[i*prime[j]]=true;
if(!(i%prime[j]))
break;
mu[i*prime[j]]=-mu[i];
}
}
for(reg int i=1;i<=n;++i)
Smu[i]=Smu[i-1]+mu[i];
return;
}
unordered_map<ll,modInt> MSmu;
inline modInt getSmu(ll n){
if(n<=S)
return Smu[n];
if(MSmu[n].x)
return MSmu[n];
modInt ans=1;
for(reg ll l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans-=modInt((r-l+1)%mod)*getSmu(n/l);
}
return MSmu[n]=ans;
}
inline modInt f(reg ll a,reg ll b,reg ll c,reg ll n){
if((a*n+b)/c==0)
return 0;
if(!a)
return modInt((n+1)%mod)*modInt((b/c)%mod);
if(!n)
return (b/c)%mod;
if(a>=c||b>=c)
return f(a%c,b%c,c,n)+modInt((a/c)%mod)*modInt(n%mod)*modInt((n+1)%mod)*inv2+modInt((b/c)%mod)*modInt((n+1)%mod);
reg ll m=(a*n+b)/c;
return modInt(n%mod)*modInt(m%mod)-f(c,c-b-1,a,m-1);
}
inline modInt getSum(reg ll n){
modInt part1=n%mod;
modInt part2=f(c,0,d,n);
modInt part3=f(a,b-1,b,n);
return part1+part2-part3;
}
bool ed;
int main(void){
Init(S);
int t;
scanf("%d",&t);
while(t--){
scanf("%lld%d%d%d%d",&n,&a,&b,&c,&d);
modInt ans=0;
for(reg ll lef=1,rig;lef<=n;lef=rig+1){
rig=n/(n/lef);
ans+=(getSmu(rig)-getSmu(lef-1))*getSum(n/lef);
}
printf("%d\n",ans.x);
}
fprintf(stderr,"%.3lf s\n",1.0*clock()/CLOCKS_PER_SEC);
fprintf(stderr,"%.3lf MiB\n",(&ed-&st)/1048576.0);
return 0;
}
标签:真分数,right,frac,int,题解,最简,modInt,left,mod 来源: https://www.cnblogs.com/Lu-Anlai/p/14957319.html