题目描述
分析
这一道题和小凯的疑惑那一道题比较像
对于两个数 (a,b),如果 (gcd(a,b)=1) ,那么它们不能表示的最大的数是 (a imes b -a -b)
对于大于 (a imes b -a -b) 的数,都可以表示出来
那么我们现在的问题就是求出小于等于 (a imes b -a -b) 的数中不能被表示出来的数的个数
观察数据范围,我们可以发现这两个数中一个是 (10^9) 级别的,另一个是 (10^5) 级别的
我们就可以从这里去找突破口,把序列依次划分为若干块,其中每一块的长度为 (b)
我们分别求出 ([0,a*b-a-b]) ([b,a*b-a-b]) ([2b,a*b-a-b]) ...中可以用 (a,b) 表示的数的个数
这样的数的数量为 (sum_{i=0}^{i*b<=a*b-a-b}((a*b-a-b-i*b)/a+1))
因为 (a,b) 是互质的,所以这样划分不会重复
我们拿最大值减去合法的方案就是不合法的方案
对于 (a,b) 不互质的情况,我们把 (a,b,q) 同时除以 (gcd(a,b))
这样的出的合法的方案数显然是相同的,因为去掉的都是不合法的方案
时间复杂度 (O(n imes t))
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
typedef long long ll;
int t;
ll a,b,q,ans,now,mmax,haha,ha;
ll gcd(ll aa,ll bb){
if(bb==0) return aa;
return gcd(bb,aa%bb);
}
int main(){
freopen("simple.in","r",stdin);
freopen("simple.out","w",stdout);
scanf("%d",&t);
while(t--){
ans=0;
scanf("%lld%lld%lld",&a,&b,&q);
if(a==b){
printf("%lld
",q-q/a);
continue;
}
now=gcd(a,b);
a/=now,b/=now;
haha=a*b-a-b;
mmax=std::min(haha,q/now);
if(a>b) std::swap(a,b);
for(ll i=1;i*b<=mmax;i++){
ans+=(mmax-i*b)/a;
}
ans+=mmax/a;
ans+=mmax/b;
if(now==1){
ans=mmax-ans;
printf("%lld
",ans);
} else {
if(q/now>=haha) ans=ans+(q/now-haha);
ans=q-ans;
printf("%lld
",ans);
}
}
return 0;
}