【LOJ#3144】[APIO2019]奇怪装置(数论)

【LOJ#3144】[APIO2019]奇怪装置(数论)

题面

LOJ

题解

突然发现\(LOJ\)上有\(APIO\)的题啦,赶快来做一做。
这题是窝考场上切了的题嗷。写完暴力之后再推了推就推出正解了。。。


考虑\(t1,t2\)两个时刻,如果两个时刻的\((x,y)\)相等的话,考虑是一种什么样的情况。
\[\begin{cases} t_1+[\frac{t_1}{B}]\equiv t_2+[\frac{t_2}{B}](\mod A)\\ t_1\equiv t_2(\mod B) \end{cases}\]
那么根据第二个条件,我们不妨令\(t_1+kB=t_2,k>0,k\in 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_1\mod 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\n",sum);return 0;}
    T=A/d*B;
    for(int i=1;i<=n;++i)
    {
        if(r[i]-l[i]+1>=T){printf("%lld\n",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\n",ans);
    return 0;
}
上一篇:【文文殿下】APIO2019游记


下一篇:CTS2019 & APIO2019 游记