其他分享
首页 > 其他分享> > [SNOI2019]数论

[SNOI2019]数论

作者:互联网

https://www.luogu.org/problemnew/show/P5330

题解

我们要求有多少个x满足:
\[ x=a_i+P*k_1=b_j+Q*k_2 \]
然后移一下:
\[ a_i+P*k_1=b_j \ (mod\ Q) \]
可以发现这个东西是有循环节的。

可以发现它的循环周期是\(lcm(P,Q)\)。

那么我们需要求的是对于每个\(a_i\),它在长度为\(Q\)的环上走,能碰到几个\(B\)。

直接算就可以了。

代码

#include<bits/stdc++.h>
#define N 1000009
using namespace std;
typedef long long ll;
ll q,p,n,m,t,a[N],b[N],sum[N],rk[N],ans,be[N],num[N];
bool vis[N];
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
inline ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
inline ll lcm(ll x,ll y){return x/gcd(x,y)*y;}
int main(){
    p=rd();q=rd();n=rd();m=rd();t=rd();t--;
    for(int i=1;i<=n;++i)a[i]=rd();
    for(int i=1;i<=m;++i)b[rd()]=1;
    for(int i=0;i<q;++i)if(!vis[i]){
        int xx=i;
        int cnt=0,last=-1;
        while(1){
            vis[xx]=1;
            rk[xx]=++cnt;be[xx]=i;
            if(last>=0)sum[xx]+=sum[last];
            sum[xx]+=b[xx];
            last=xx;
            xx=(xx+p)%q;
            if(vis[xx])break;
        }
        num[i]=sum[last];
    }
    ll len=lcm(q,p);
    for(int i=1;i<=n;++i)if(a[i]<=t){
        ll le=t-a[i],id=a[i]%q;
        ans+=(le/len)*num[be[id]];le%=len;le/=p;
        ll yy=(id+le*p)%q;
        if(rk[yy]>=rk[id])ans+=sum[yy]-sum[id]+b[id];
        else ans+=num[be[id]]-sum[id]+b[id]+sum[yy];
    }
    cout<<ans;
    return 0;
}

标签:数论,sum,id,xx,num,ans,SNOI2019,ll
来源: https://www.cnblogs.com/ZH-comld/p/10821574.html