找呀找呀找规律
明显是以最小公倍数来循环的
所以就分最小公倍数这一段 和 最后多出最小公倍数的部分来算
在这之中还要优化 就是有些连续的段 在a和在b里的编号都一样
自己写写就找到规律了
话说有个地方不懂 为什么AC代码要int64?
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#define inf 0x3f3f3f3f
using namespace std;
__int64 gcm(int p,int q)
{
if (p<q) return gcm(q,p);
if (p%q==0) return q;
else return gcm(q,p%q);
}
__int64 LCM(int p,int q)
{
return p/gcm(p,q)*q;
}
__int64 t,n,a,b,ans;
int main()
{
__int64 tmp,i,nn,nres,lcm,ans1,cnt,j;
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d%I64d",&n,&a,&b);
if((n<=a&&n<=b)||a==b)
{
printf("0\n");
continue;
}
if(a%b==0||b%a==0)
{
if(a<b)
{
tmp=a;
a=b;
b=tmp;
}
nn=n/a;
nres=(n%a)>b?(n%b):0;
ans=b*(nn*b+nres);
printf("%I64d\n",ans);
continue;
}
lcm=min(LCM(a,b),n);//取小的一个循环
nn=n/lcm;
nres=n%lcm;//多出一个整循环的部分
cnt=0;i=0;j=0;ans=0;
while(lcm>cnt)
{
if(j>=b) j-=b;
if(i>=a) i-=a;
if((a-i)>(b-j)) tmp=b-j;//取小的一个 这一段的差都是一样的
else tmp=a-i;
if(tmp>(lcm-cnt)) tmp=lcm-cnt;
if(i>j) ans+=tmp*(i-j);
else ans+=tmp*(j-i);
i+=tmp;
j+=tmp;
cnt+=tmp;
}
cnt=0;i=0;j=0;ans1=0;
while(nres>cnt)
{
if(j>=b) j-=b;
if(i>=a) i-=a;
if((a-i)>(b-j)) tmp=b-j;
else tmp=a-i;
if(tmp>(nres-cnt)) tmp=nres-cnt;
if(i>j) ans1+=tmp*(i-j);
else ans1+=tmp*(j-i);
i+=tmp;
j+=tmp;
cnt+=tmp;
}
printf("%I64d\n",nn*ans+ans1);
}
return 0;
}