JZOJ 5746. 和

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huangjingyuan107/article/details/80461474

致歉信

我作为博主,没有实时更新这片博客,感到很抱歉。

题目

Σi=1nik(mod m)
其中,m的最小值因子不超过300000
有多组数据。数据数小于等于3000.
n,k,m1018

题解

这道题目的部分分很好拿,但就是坑。
对于k1000,直接上一波斯特林数就好了。
什么,没拿到应有的分数?!
检查后发现,是在预处理Si,j漏了快速加。
所以对于每个乘号都要检查。
对于n107,直接快速幂肯定会T。
我竟然漏想了线筛?!
其实不用快速加,直接看下面一段过程。

LL ksj(LL x,LL y){
    x%=m;y%=m;
    LL tmp=(LL)((DB)x*y/m+1e-8)*m;
    return (x*y-tmp+m)%m;
}

由于xytmp溢出的部分是一样的,所以他俩相减之后对答案没有影响了。
加上108,是为了避免精度问题。
然后就可以愉快地线筛了。

LL ksm(LL x,LL y){
    LL rs=1;x%=m;
    for(;y;y>>=1,x=ksj(x,x))if(y&1)rs=ksj(rs,x);
    return rs;
}
void pre(){
    LL i,j;
    f[1]=1;
    fo(i,2,N-10){
        if(!bz[i]){
            pri[++pri[0]]=i;
            f[i]=ksm(i,k);
        }
        fo(j,1,pri[0]){
            if(i*pri[j]>N-10)break;
            bz[i*pri[j]]=1;
            f[i*pri[j]]=ksj(f[i],f[pri[j]]);
            if(i%pri[j]==0)break;
        }
    }
} 

接下来还有这一档部分分:μ2(m)=1
m的质因数两两互不相同。
直接用中国剩余定理搞一波得了。
重新说一遍中国剩余定理吧。
假设现在方程组内有k个方程:
Xa1 (mod p1)
Xa2 (mod p2)
……
Xak (mod pk)
Ai=mpi,Ti=Aipi2%pi
则在模m=Πi=1kpi的情况下有唯一解。
XΣi=1kaiAiTi(mod m)
这是我的70分代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 10000010
#define M 100010
#define DB long double
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
LL sum[N],qu[M];
LL m,k,kk,T,n,x,i,j,mx,ans,temp;
LL A1,A2;
LL s1[N],S[1002][1002];
LL f[N],pri[N],cnt;
LL p[N],b[M],t[N],a[N];
bool bz[N];
LL ksj(LL x,LL y,LL m){
    x%=m;y%=m;
    LL tmp=(LL)((DB)x*y/m+1e-8)*m;
    return (x*y-tmp+m)%m;
}
void pres(){
    LL i,j;
    S[0][0]=1;
    fo(i,1,1000)fo(j,1,i)S[i][j]=(S[i-1][j-1]+ksj(S[i-1][j],i-1,m))%m;
}
LL ksm(LL x,LL y,LL m){
    LL rs=1;x%=m;
    for(;y;y>>=1,x=ksj(x,x,m))if(y&1)rs=ksj(rs,x,m);
    return rs;
}
LL get1(LL n,LL k){
    LL rs=1,i;
    fd(i,n,n-k+1){
        if(i%k==0){
            rs=ksj(rs,i/k,m);
        }else rs=ksj(rs,i,m);
    }
    return rs%m;
}
void pre(){
    LL i,j;
    f[1]=1;
    fo(i,2,N-10){
        if(!bz[i]){
            pri[++pri[0]]=i;
            f[i]=ksm(i,k,m);
        }
        fo(j,1,pri[0]){
            if(i*pri[j]>N-10)break;
            bz[i*pri[j]]=1;
            f[i*pri[j]]=ksj(f[i],f[pri[j]],m);
            if(i%pri[j]==0)break;
        }
    }
}
void pre1(){
    LL i,j;
    f[1]=1;
    fo(i,2,300000){
        if(!bz[i]){
            pri[++pri[0]]=i;
            f[i]=ksm(i,k,m);
        }
        fo(j,1,pri[0]){
            if(i*pri[j]>300000)break;
            bz[i*pri[j]]=1;
            f[i*pri[j]]=ksj(f[i],f[pri[j]],m);
            if(i%pri[j]==0)break;
        }
    }
}
void work(LL n){
    LL i;
    fo(i,1,cnt){
        A1=sum[p[i]];
        A2=sum[n%p[i]];
        b[i]=(ksj(A1,n/p[i],p[i])+A2)%p[i];
    }
    ans=0;
    fo(i,1,cnt){
        ans=(ans+ksj(ksj(a[i],b[i],m),t[i],m))%m;
    }
    printf("%lld\n",ans);
}
int main(){
    scanf("%lld%lld%lld",&m,&k,&T);
    fo(i,1,T)scanf("%lld",&qu[i]),mx=max(mx,qu[i]);
    if(mx<=10000000){
        pre();
        fo(i,1,10000000)sum[i]=(sum[i-1]+f[i])%m;
        fo(i,1,T)printf("%lld\n",sum[qu[i]]);
        return 0;
    }
    if(k<=1000){
        pres();
        fo(i,1,T){
            n=qu[i];
            ans=0;
            s1[0]=n%m;
            fo(kk,1,k){
                s1[kk]=get1(n+1,kk+1);
                fo(j,0,kk-1){
                    temp=ksj(S[kk][j],s1[j],m);
                    s1[kk]=(s1[kk]-((j+kk)&1?-1:1)*temp%m+m)%m;
                }
            }
            ans=s1[k]%m;
            printf("%lld\n",ans);
        }
        return 0;
    }
    pre1();
    fo(i,1,300000)sum[i]=(sum[i-1]+f[i])%m;
    x=m;
    fo(i,1,25997)if(x%pri[i]==0){
        if(x%(pri[i]*pri[i])==0){
            printf("0");
            return 0;
        }
        a[++cnt]=m/pri[i];
        p[cnt]=pri[i];
        t[cnt]=ksm(a[cnt],p[cnt]-2,p[cnt]);
        x/=pri[i];
        if(x==1)break;
    }
    fo(i,1,T)work(qu[i]);
    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页