模拟+数学
连续的一段可直接统计,需要算一下gcd,简单题
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef __int64 lld;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,a,b;
scanf("%d%d%d",&n,&a,&b);
lld m=(lld)a/(lld)gcd(a,b)*(lld)b;
lld num=(lld)n/m,sum=(lld)n%m;
lld tmp=0,ans=0;
for(lld i=0;i<m;)//求最小公倍数部分
{
if(i%a==i%b)
{
i+=(lld)min(a-i%a,b-i%b);//余数相同部分,直接跳过,i移到i%a==0或i%b==0 最近的那个
//min(a-i%a,b-i%b) 就是需要移到的最小值,下面都是一样的。
}
else
{
tmp+=abs((lld)(i%a-i%b))*(lld)min(a-i%a,b-i%b); //加上这一段的(差值*段长)
i+=(lld)min(a-i%a,b-i%b);
}
}
for(lld i=0;i<sum;) //余数部分
{
if(i%a==i%b)
{
i+=(lld)min(a-i%a,b-i%b);
}
else
{
ans+=abs((lld)(i%a-i%b))*(lld)min((lld)min(a-i%a,b-i%b),sum-i);
i+=(lld)min((lld)min(a-i%a,b-i%b),sum-i);
}
}
ans+=tmp*num;
printf("%I64d\n",ans);
}
}