其他分享
首页 > 其他分享> > 数论 筛法+拉格朗日插值 lgP5493题解

数论 筛法+拉格朗日插值 lgP5493题解

作者:互联网

卡完常后来造福一下人类

如何从4.80s卡到920ms.jpg

本题解的复杂度为 \(O(\frac {n^{3/4}} {\log n})\),然而标算是 \(O(\frac {n^{2/3}} {\log^{1/3} n})\) 的。。。

有时间尝试卡一下标算,但是看样子好像已经卡过一些了,不知道能不能比我这个代码快(

首先亮出经典 DP:

\[f(n,id)=f(n,id-1)-p_{id}^k \times (f(\frac n {p_{id}},id-1)-f(p_{id},id-1)) \]

然后你写完之后稍微卡一下,再吸个氧就能得到4.80s的代码了。

稍微卡一下指把DP的部分中的int和ll分开,并且线性筛进行了一些神奇的优化(

然后我们开始卡。

首先加了一个FastMod,速度变成了2.57s

然后众所周知的是,实数除法比整数除法要快,变成了1.31s。

然后我们知道线性筛的原理是 用自身最小的质因子筛掉自己,那么我们没有必要用除法,将其记录下来即可,1.13s。

然后我们将减法优化改成暴力取模,发现变成了1.06s。

然后由于我的DP过程中边界是这样判的:

for(;j<=tot&&pri[i]<=(m1=w[j]*invp[i]);++j)

我们发现只需要将pri[top+1]改为INF就能够避免掉前面的那个j<=tot,这次卡进了1s,970ms。

然后由于我们DP时每次都计算了一遍sum[i-1]+p,我们就新开了一个变量s将其存下来,920ms。

upd:把f中的n故技重施能卡到915ms。

不知道还能不能卡/youl

upd:把前面的一些“优化”删掉之后跑了885ms。

#include<cstdio>
#include<cmath>
typedef long long ll;
typedef __uint128_t L;
typedef unsigned long long ull;
const ll M=2e5+5;
int k,p,a[15],ifac[15],sl[15],sr[15];
int S,id1[M],id2[M];ll tot,g[M<<1];ll n,w[M<<1];
int top,F[17985],pri[17985],sum[17985],pos[M];bool zhi[M];
double invp[17985];
struct FastMod{
    ull b,m;
    FastMod(ull b):b(b),m(ull((L(1)<<64)/b)){}
    friend inline ull operator%(const ull&a,const FastMod&mod){
        ull q=(L(mod.m)*a)>>64;
        ull r=a-q*mod.b;
        return r>=mod.b?r-mod.b:r;
    }
}mod(2);
inline int pow(int a,int b){
	register int ans=1;
	for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;
	return ans;
}
inline void init(){
	register int i;k+=2;a[1]=sl[0]=sr[k+1]=ifac[0]=ifac[1]=1;
	for(i=2;i<=k;++i)a[i]=(a[i-1]+pow(i,k-2))%mod,ifac[i]=1ll*(p-p/i)*ifac[p%i]%mod;
	for(i=2;i<=k;++i)ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
	for(i=1;i<=k;++i)a[i]=1ll*ifac[i-1]*(k-i&1?p-ifac[k-i]:ifac[k-i])%mod*a[i]%mod;
}
inline int f(const int&n){
	register int i,N=n+p;register ull ans=0;
	for(i=1;i<=k;++i)sl[i]=1ll*sl[i-1]*(N-i)%mod;
	for(i=k;i>=1;--i)sr[i]=1ll*sr[i+1]*(N-i)%mod;
	for(i=1;i<=k;++i)ans+=1ll*sr[i+1]*sl[i-1]%mod*a[i];
	return ans%mod;
}
inline void sieve(const int&n){
	register int i=6,j,x,m;top=2;
	F[1]=pow(pri[1]=2,k);F[2]=pow(pri[2]=3,k);
	sum[1]=F[1];sum[2]=F[1]+F[2];
	invp[1]=1./2*(1+1e-15);invp[2]=1./3*(1+1e-15);
	do{
		if(!zhi[m=i-1]&&i-1<=n){
			pri[++top]=m;sum[top]=(sum[top-1]+(F[top]=pow(m,k)))%mod;
			invp[top]=1./m*(1+1e-15);
		}
		for(j=3;j<=top&&(x=m*pri[j])<=n;++j){
			zhi[x]=true;if((pos[x]=j)==pos[m])break;
		}
		if(!zhi[m=i+1]&&i+1<=n){
			pri[++top]=m;sum[top]=(sum[top-1]+(F[top]=pow(m,k)))%mod;
			invp[top]=1./m*(1+1e-15);
		}
		for(j=3;j<=top&&(x=m*pri[j])<=n;++j){
			zhi[x]=true;if((pos[x]=j)==pos[m])break;
		}
	}while((i+=6)-1<=n);pri[++top]=p;invp[top]=0;
}
void Solve(const ll&n){
	const ll&n9=n/1e9;
	register int i,j,k,s;register ll m,L=1,R;
	for(;L<=n;L=R+1,--g[tot]){
		R=n/(m=w[++tot]=1.*n/L);g[(m<=S?id1[m]:id2[R])=tot]=f(m%mod);
	}
	for(i=1;i<=top;++i){
		s=sum[i-1]+p;
		for(j=1;pri[i]<=(m=w[j]*invp[i]);++j){
			g[j]+=1ll*F[i]*(s-g[m<=S?id1[m]:id2[int(1.*n/m)]])%mod;
			if(g[j]>=p)g[j]-=p;
		}
	}
}
signed main(){
	register int i=1;register ull ans=0;
	scanf("%lld%d%d",&n,&k,&p);mod=FastMod(p);
	sieve(S=sqrt(n));init();Solve(n);
	for(register ll m;i<=S;++i){
		m=1.*n/i;
		ans+=1ll*i*i%mod*g[m<=S?id1[m]:id2[ll(1.*n/m)]]%mod;
		if(ans>=p)ans-=p;
	}
	printf("%d",ans);
}

标签:筛法,int,题解,ll,register,lgP5493,ans,id,mod
来源: https://www.cnblogs.com/lmpp/p/15784940.html