P4449 于神之怒加强版
Genius_Star · · 题解
一个唯一一篇用杜教筛的题解。
题意:
求:
思路:
直接推式子:
老套路,令
定义
我们需要计算
因为
因为:
所以:
预处理一下
杜教筛时只需要预处理
完整代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=5e6+10,K=1e5+10,mod=1e9+7;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
ll T,n,m,k,cnt=0;
ll S[N],A[N],P[N],M[N];
bool f[N];
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1ll)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1ll;
}
return ans;
}
void init(){
M[1]=1;
for(int i=2;i<N;i++){
if(!f[i]){
M[i]=-1;
P[++cnt]=i;
}
for(ll j=1;j<=cnt&&i*P[j]<N;j++){
f[i*P[j]]=1;
if(i%P[j]==0)
break;
else
M[i*P[j]]=-M[i];
}
}
for(int i=1;i<N;i++)
S[i]=qpow(i,k);
for(ll i=1;i<K;i++){
if(!M[i])
continue;
for(ll j=i;j<K;j+=i)
A[j]=(A[j]+M[i]*S[j/i]+mod)%mod;
}
for(int i=2;i<N;i++)
S[i]=(S[i]+S[i-1])%mod;
for(int i=2;i<K;i++)
A[i]=(A[i]+A[i-1])%mod;
}
ll H(ll n){
if(A[n])
return A[n];
ll ans=S[n],l,r;
for(l=2;l<=n;l=r+1){
r=n/(n/l);
ans=(ans-((r-l+1)*H(n/l))%mod+mod)%mod;
}
A[n]=ans;
return ans;
}
ll solve(ll n,ll m){
ll ans=0,l,r;
if(n>m)
swap(n,m);
for(l=1;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans=(ans+((((n/l)*(m/l))%mod)*((H(r)-H(l-1)+mod)%mod))%mod)%mod;
}
return ans;
}
int main(){
T=read(),k=read();
init();
while(T--){
n=read(),m=read();
write(solve(n,m));
putchar('\n');
}
return 0;
}