1. 程式人生 > >p3172 選數

p3172 選數

傳送門

分析

對這個$f(k)$整除分塊,用杜教篩搞出$\mu$的部分然後另一部分快速冪即可

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include
<vector> #include<set> #include<map> #include<stack> using namespace std; const int N = 5e6; const int mod = 1e9+7; int p[N+10],mu[N+10]; bool is[N+10]; map<int,int>MU; inline void init(){ int i,j,cnt=0; mu[1]=1; for(i=2;i<=N;i++){ if(!is[i])p[++cnt]=i,mu[i]=-1
; for(j=1;j<=cnt,i*p[j]<=N;j++){ is[p[j]*i]=1; if(i%p[j]==0){ mu[p[j]*i]=0; break; } mu[p[j]*i]=-mu[i]; } } for(i=2;i<=N;i++)mu[i]=(mu[i]+mu[i-1]+mod)%mod; } inline int go(int x){ if(x<=N)return mu[x];
if(MU[x])return MU[x]; int res=1,le=2,ri; for(;le<=x;le=ri+1){ ri=x/(x/le); res=(res-(long long)(ri-le+1)*go(x/le)%mod+mod)%mod; } return MU[x]=res; } inline int pw(int x,int p){ int res=1; while(p){ if(p&1)res=(long long)res*x%mod; x=(long long)x*x%mod; p>>=1; } return res; } int main(){ int n,m,p,k,L,R,le=1,ri,Ans=0; scanf("%d%d%d%d",&p,&k,&L,&R); n=R/k,m=(L-1)/k; init(); for(;le<=n;le=ri+1){ if(m/le)ri=min(n/(n/le),m/(m/le)); else ri=n/(n/le); Ans=(Ans+(long long)(go(ri)-go(le-1)+mod)%mod*pw(n/le-m/le,p)%mod)%mod; } printf("%d\n",Ans); return 0; }