【LOJ#3144】[APIO2019]奇怪装置(数论)
题面
题解
突然发现(LOJ)上有(APIO)的题啦,赶快来做一做。
这题是窝考场上切了的题嗷。写完暴力之后再推了推就推出正解了。。。
考虑(t1,t2)两个时刻,如果两个时刻的((x,y))相等的话,考虑是一种什么样的情况。
[egin{cases}
t_1+[frac{t_1}{B}]equiv t_2+[frac{t_2}{B}](mod A)\
t_1equiv t_2(mod B)
end{cases}]
那么根据第二个条件,我们不妨令(t_1+kB=t_2,k>0,kin Z)。
那么带到第一个式子中就是:
[t_1+[frac{t_1}{B}]equiv t_1+kB+k+[frac{t1}{B}](mod A)
]
化简之后得到
[k(B+1)equiv 0(mod A)
]
而(A,B)都是常量,所以(frac{A}{gcd(A,B+1)}|k)。令(g=frac{A}{gcd(A,B+1)}),所以(g|k)。
所以(k)要是(g)的倍数的时候才会满足这个条件。而(t_1mod B)的取值共有(B)种,所以不难得到循环节就是(T=gB)。
那么把所有(l,r)取模之后得到一条条的线段,线段在([0,T))的覆盖区间总长度就是答案,可以很简单的差分计算出答案。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
#define ll long long
#define MAX 1000100
inline ll read()
{
ll x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
ll n,sum,l[MAX],r[MAX],A,B,d,T,ans;
multiset<pair<ll,int> >S;
#define mp make_pair
void Add(ll l,ll r){S.insert(mp(l,1));S.insert(mp(r+1,-1));}
int main()
{
n=read();A=read();B=read();d=__gcd(A,B+1);
for(int i=1;i<=n;++i)l[i]=read(),r[i]=read(),sum+=r[i]-l[i]+1;
if(1.0*A*B/d>1e18){printf("%lld
",sum);return 0;}
T=A/d*B;
for(int i=1;i<=n;++i)
{
if(r[i]-l[i]+1>=T){printf("%lld
",T);return 0;}
if(l[i]/T!=r[i]/T)Add(l[i]%T,T-1),Add(0,r[i]%T);
else Add(l[i]%T,r[i]%T);
}
S.insert(mp(T,0));
ll lst=-1,c=0;
for(auto a:S)
{
if(c>0)ans+=a.first-lst;
c+=a.second;
lst=a.first;
}
printf("%lld
",ans);
return 0;
}