这个网上找不到题解嘛 那我就来写一发!
(式子略)
不是我不想写 是我真的不会用markdown
我立一发flag 除夕我要学markdown
完成题解补完计划
Ans=2∑i=1n∑j=1ii∗σ(ij)−∑i=1ni∗σ(i2)
因为
∑i=1nσ(i∗n)====∑i=1n∑a|i∑b|na∗nb[(a,b)=1]∑b|nnb∑a=1n⌊na⌋∗a∑d|(a,b)μ(d)∑b|nnb∑d|bμ(d)∑a=1nd⌊nad⌋∗ad∑d|nμ(d)∗d∑b|ndnbd∑a=1nd⌊nda⌋∗a
所以
∑i=1n∑j=1ii∗σ(ij)====∑i=1ni∑d|iμ(d)∗d∑b|idibd∑a=1id⌊ida⌋∗a∑d=1nμ(d)∗d∑i=1⌊nd⌋id∑b|ib∑a=1ia⌊ia⌋∑d=1nμ(d)∗d2∑i=1⌊nd⌋i∑b|ib∑a=1ia⌊ia⌋∑d=1nμ(d)∗d2∑i=1⌊nd⌋i∗sumd(i)∗ssumd(i)
其中有 sumd(n)=∑d|nd 和 ssumd(n)=∑ni=1sumd(i)
其实到这一步我们就可以
O(n)
预处理
O(n√)
询问了
但是复杂度高了点 刚好卡不进1s 反正我撑死1.5s左右
然后我们再推
ret=====∑d=1nμ(d)∗d2∑i=1⌊nd⌋i∗sumd(i)∗ssumd(i)∑i=1n∑d|iμ(id)∗(id)2∗d∗sums(d)∗ssumd(d)∑i=1n∑d|iμ(d)∗d2∗id∗sums(id)∗ssumd(id)∑i=1n∑d|iμ(d)∗d∗i∗sums(id)∗ssumd(id)∑i=1nF(i)
这样的话 我们就可以我们就可以 O(nlnn) 预处理 O(1) 询问了
上代码
先是我打的线性预处理 根号查询
妥妥T
#include<cstdio>
#include<cstdlib>
#include<algorithm>
typedef long long ll;
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int P=1e9+7;
const int maxn=1000000;
int prime[200000],num;
int miu[maxn+5],sum1[maxn+5],sum2[maxn+5];
ll ssumd[maxn+5],sumd[maxn+5],t1[maxn+5],t2[maxn+5]; int d[maxn+5];
ll sumd2[maxn+5],t12[maxn+5],t22[maxn+5];
ll F[maxn+5],G[maxn+5];
inline void Pre(){
miu[1]=1; sumd[1]=1; sumd2[1]=1;
for (int i=2;i<=maxn;i++){
if (!d[i]){
d[i]=prime[++num]=i;
miu[i]=-1;
sumd[i]=1+i,t1[i]=1+i,t2[i]=i;
sumd2[i]=1LL+i+(ll)i*i,t12[i]=1LL+i+(ll)i*i,t22[i]=(ll)i*i;
}
for (int j=1;j<=num && (ll)i*prime[j]<=maxn;j++){
d[i*prime[j]]=prime[j]; int k=i*prime[j],p=prime[j];
if (k==4)
int c=1;
if (i%prime[j]==0){
miu[k]=0;
t2[k]=t2[i]*p,t1[k]=t1[i]+t2[k],sumd[k]=sumd[i]/t1[i]*t1[k];
t22[k]=t22[i]*p*p,t12[k]=t12[i]+t22[i]*((ll)p*p+p),sumd2[k]=sumd2[i]/t12[i]*t12[k];
break;
}
miu[i*p]=miu[i]*miu[p];
sumd[k]=sumd[i]*sumd[p],t1[k]=1+p,t2[k]=p;
sumd2[k]=sumd2[i]*sumd2[p],t12[k]=1LL+p+(ll)p*p,t22[k]=(ll)p*p;
}
}
for (int i=1;i<=maxn;i++){
sum2[i]=((ll)i*i%P*((P+miu[i])%P)%P+sum2[i-1])%P;
sum1[i]=((ll)i*((P+miu[i])%P)%P+sum1[i-1])%P;
ssumd[i]=(ssumd[i-1]+sumd[i])%P;
F[i]=(F[i-1]+(ll)i*(sumd[i]%P)%P*ssumd[i]%P)%P;
G[i]=(G[i-1]+(ll)i*(sumd2[i]%P)%P)%P;
}
}
inline int Solve(int n){
ll ret=0; int l,r;
for (l=1;l*l<=n;l++) ret+=(ll)(sum2[l]-sum2[l-1]+P)*F[n/l]%P;
for (int t=n/l,r;l<=n;l=r+1,t--)
r=n/t,ret+=(ll)(sum2[r]-sum2[l-1]+P)*F[t]%P;
return ret%P;
}
int main(){
int n,Q,Case=0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(Q); Pre();
while (Q--){
read(n);
printf("Case #%d: %lld\n",++Case,((ll)Solve(n)*2+P-G[n])%P);
}
return 0;
}
然后发现根本不需要根号 nlnn预处理可以O(1)查询
然后改改就过了
我从未写线性筛写成这副模样过
#include<cstdio>
#include<cstdlib>
#include<algorithm>
typedef long long ll;
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int P=1e9+7;
const int maxn=1000000;
int prime[200000],num;
int miu[maxn+5];
ll mul[maxn+5];
ll ssumd[maxn+5],sumd[maxn+5],t1[maxn+5],t2[maxn+5]; int d[maxn+5];
ll sumd2[maxn+5],t12[maxn+5],t22[maxn+5];
ll F[maxn+5],G[maxn+5];
inline void Pre(){
miu[1]=1; sumd[1]=1; sumd2[1]=1;
for (int i=2;i<=maxn;i++){
if (!d[i]){
d[i]=prime[++num]=i;
miu[i]=-1;
sumd[i]=1+i,t1[i]=1+i,t2[i]=i;
sumd2[i]=1LL+i+(ll)i*i,t12[i]=1LL+i+(ll)i*i,t22[i]=(ll)i*i;
}
for (int j=1;j<=num && (ll)i*prime[j]<=maxn;j++){
d[i*prime[j]]=prime[j]; int k=i*prime[j],p=prime[j];
if (k==4)
int c=1;
if (i%prime[j]==0){
miu[k]=0;
t2[k]=t2[i]*p,t1[k]=t1[i]+t2[k],sumd[k]=sumd[i]/t1[i]*t1[k];
t22[k]=t22[i]*p*p,t12[k]=t12[i]+t22[i]*((ll)p*p+p),sumd2[k]=sumd2[i]/t12[i]*t12[k];
break;
}
miu[i*p]=miu[i]*miu[p];
sumd[k]=sumd[i]*sumd[p],t1[k]=1+p,t2[k]=p;
sumd2[k]=sumd2[i]*sumd2[p],t12[k]=1LL+p+(ll)p*p,t22[k]=(ll)p*p;
}
}
for (int i=1;i<=maxn;i++){
ssumd[i]=(ssumd[i-1]+sumd[i])%P;
G[i]=(G[i-1]+(ll)i*(sumd2[i]%P)%P)%P;
}
for (int i=1;i<=maxn;i++)
mul[i]=ssumd[i]*sumd[i]%P;
for (int i=1;i<=maxn;i++)
if (miu[i])
for (int j=i;j<=maxn;j+=i){
if (miu[i]==1)
F[j]+=(ll)i*j%P*mul[j/i]%P;
else
F[j]+=P-(ll)i*j%P*mul[j/i]%P;
if (F[j]>=P) F[j]-=P;
}
for (int i=1;i<=maxn;i++){
F[i]+=F[i-1]; if (F[i]>=P) F[i]-=P;
}
}
int main(){
int n,Q,Case=0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(Q); Pre();
while (Q--){
read(n);
printf("Case #%d: %lld\n",++Case,((ll)F[n]*2+P-G[n])%P);
}
return 0;
}