luogu P5330 [SNOI2019]数论

传送门

可以枚举一个\(a_i\),然后就是求\(\sum_{x=0}^{\lfloor\frac{t-1-a_i}{p}\rfloor}[px+a_i \in B(\mod q)]\)

可以发现所有\(px+a_i\mod q\)的值是成环的,就可以求出这个环所有前缀中\(\in B\)的元素个数,然后那个式子的值就是完整的环出现次数*环内\(B\)元素个数+剩下部分的\(B\)元素个数.并且模\(\gcd(p,q)\)同余的\(a_i\),环内元素构成的集合是一样的,所以可以枚举\(d\),然后把\(a_i =d\mod \gcd(p,q)\)\(a_i\)放在一起处理

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double

using namespace std;
const int N=1e6+10;
LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
LL mi[N],p,q,d,lcm,n,m,a[N],b[N],t,ans,s[N<<1],ps[N];
bool v[N];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
bool cmp(int aa,int bb){return aa%d<bb%d;}

int main()
{
    memset(mi,0x3f,sizeof(mi));
    p=rd(),q=rd(),n=rd(),m=rd(),t=rd()-1;
    for(int i=1;i<=n;++i) a[i]=rd();
    for(int i=1;i<=m;++i) b[i]=rd();
    if(p>q)
    {
        swap(p,q),swap(n,m);
        for(int i=1;i<=n||i<=m;++i) swap(a[i],b[i]);
    }
    for(int i=1;i<=m;++i) v[b[i]]=1;
    d=gcd(p,q),lcm=p/d*q;
    sort(a+1,a+n+1,cmp);
    for(int i=0,j=1;i<d;++i)
    {
        LL lm=q/d;
        for(int k=1,l=i;k<=lm;++k,l=(l+p)%q)
            s[k]=s[k+lm]=v[l],ps[l]=k;
        for(int k=1;k<=lm*2;++k) s[k]+=s[k-1];
        while(j<=n&&a[j]%d==i)
        {
            int ii=ps[a[j]],len=((t-a[j])%lcm+p)/p;
            ans+=(t-a[j])/lcm*s[lm]+s[ii+len-1]-s[ii-1];
            ++j;
        }
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2019-05-02 12:02  ✡smy✡  阅读(248)  评论(0编辑  收藏  举报