HDU 4611 - Balls Rearrangement(2013MUTC2-1001)(数学,区间压缩)

时间:2023-03-09 16:02:50
HDU 4611 - Balls Rearrangement(2013MUTC2-1001)(数学,区间压缩)

以前好像是在UVa上貌似做过类似的,mod的剩余,今天比赛的时候受baofeng指点,完成了此道题

此题题意:求sum(|i%A-i%B|)(0<i<N-1)

A、B的循环节不同时,会有重叠,重叠后的区间里的数的值相等(可以证明,这里不给出了),然后压缩区间端点值,直接求区间和即可

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define LL long long
using namespace std;
LL abs(LL a,LL b)
{
return (a-b)>(b-a)?(a-b):(b-a);
}
LL gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}
LL lcm(LL a,LL b)
{
return a/gcd(a,b)*b;
}
LL t[200005];
LL d[200005];
LL f[200005];
int main()
{
int T;
LL n,a,b;
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d%I64d",&n,&a,&b);
LL x=lcm(a,b);
LL A=(x/a);
LL B=(x/b);
LL ct=0;
for(LL i=1;i<=A;i++)
{
t[i]=i*a;
}
for(LL i=1;i<=B;i++)
{
t[A+i]=i*b;
}
sort(t+1,t+A+B+1);
d[ct++]=0;
d[ct++]=t[1];
for(LL i=2;i<=A+B;i++)
{
if(t[i]!=t[i-1])
d[ct++]=t[i];
}
for(LL i=1;i<ct;i++)
{
f[i]=abs(d[i-1]%a,d[i-1]%b)*(d[i]-d[i-1]);
}
for(LL i=1;i<ct;i++)
f[i]+=f[i-1];
LL ans=0,INT=n/x,MOD=n%x;
ans+=INT*f[ct-1];
for(LL i=1;i<ct;i++)
{
if(k<=d[i])
{
ans+=f[i-1]+abs(d[i-1]%a,d[i-1]%b)*(MOD-d[i-1]);
break;
}
}
printf("%I64d\n",ans);
}
return 0;
}