题解 | #简单的数学题#
简单的数学题
https://ac.nowcoder.com/acm/contest/16832/B
B题:简单的数学题
大概思路是杜教筛+莫比乌斯反演+枚举+整除分块优化+记忆化优化
代码如下:
#include<iostream>
#include<string.h>
#include<unordered_map>
#define lint long long
#define mod 1000000007
#define pren 5000007
#define dnprime 5000007
using
namespace
std;
bool isprime[pren];
lint prime[dnprime],nprime;
lint myu[pren],smyu[pren];
unordered_map<lint,lint> bsmyu;
unordered_map<lint,lint> preans,subpreans;
void prework(){
memset(isprime,true,sizeof(isprime));
memset(myu,0,sizeof(myu));
nprime=0;
myu[0]=0,myu[1]=1;
for(lint i=2;i<pren;i++){
if(isprime[i]){
prime[nprime]=i;
myu[i]=-1;
nprime++;
}
for(lint j=0;j<nprime&&i*prime[j]<pren;j++){
isprime[i*prime[j]]=false;
if(i%prime[j]==0){
myu[i*prime[j]]=0;
break;
}
else{
myu[i*prime[j]]=-myu[i];
}
}
}
smyu[0]=0;
for(int i=1;i<pren;i++){
smyu[i]=smyu[i-1]+myu[i];
}
return;
}
lint find_smyu(lint x){
if(x<pren) return smyu[x];
if(bsmyu[x]) return bsmyu[x];
lint ans=1;
for(lint l=2,r;l<=x;l=r+1){
r=x/(x/l);
ans-=(r-l+1)*(find_smyu(x/l));
}
return bsmyu[x]=ans;
}
lint subcal(lint x){
if(subpreans[x]) return subpreans[x];
lint ans=x;
for(lint l=2,r;l<=x;l=r+1){
r=x/(x/l);
ans=( ans
+
(
((r+l)*(r-l+1)/2)%mod
*
((1+x/l)*(x/l)/2)%mod
)%mod
+
(
(x*l)%mod
*
(x/(l-1)-x/l)
)%mod
-
(
((l*(l-1))/2)%mod
*
((x/(l-1)-x/l)*(x/(l-1)+x/l+1))%mod
)%mod
)%mod;
}
if(ans<0) ans+=mod;
return subpreans[x]=ans;
}
lint cal(lint x){
if(preans[x]) return preans[x];
lint ans=0;
for(lint l=1,r;l<=x;l=r+1){
r=x/(x/l);
ans=(ans+(find_smyu(r)-find_smyu(l-1))*(subcal(x/l)))%mod;
}
if(ans<0) ans+=mod;
return preans[x]=ans;
}
signed main(){
prework();
int t;
lint x;
scanf("%d",&t);
while(t--){
scanf("%lld",&x);
printf("%lld\n",cal(x));
}
return EOF+1;
}