51nod1584:加权约数和(数论+线性筛)
来源:互联网 发布:黑马程序员html 编辑:程序博客网 时间:2024/05/29 18:42
离退役不远了,我依然很菜很菜,所以以后博客不再面向对象了,只为自己看懂。
题面
题意:求
其中
分类讨论
考虑
由kscla的数表,有
先枚举a,到i,到b,到j,在把中括号用
设右半部分为
考虑f,有
根据杜教筛的柿子和套路,将f差分,设为g,有
复杂度nln(n)。
这是Kscla的博客,两篇都有错,对着看就好了。
这个T了,也懒得调了。
#include <iostream>#include <fstream>#include <algorithm>#include <cmath>#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define mmst(a, b) memset(a, b, sizeof(a))#define mmcp(a, b) memcpy(a, b, sizeof(b))typedef long long LL;const int N=1001000,nn=1000000;LL mo=1e9+7;int T,n;LL prime[N],num,u[N],f[N],miu[N];LL g[N],h[N],p[N];int ans[N],c[N],hh[N];bool b[N];void read(int &hy){ hy=0; char cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') { hy=(hy<<3)+(hy<<1)+cc-'0'; cc=getchar(); }}int main(){ p[1]=miu[1]=u[1]=f[1]=1; for(int i=2;i<=nn;i++) { if(!b[i]) { prime[++num]=i; u[i]=i; miu[i]=-1; f[i]=i+1; p[i]=((LL)i*i%mo+i+1)%mo; } for(int j=1;j<=num&&prime[j]*i<=nn;j++) { LL pj=prime[j]; int ipj=i*pj; b[ipj]=1; if(i%pj==0) { u[ipj]=u[i]*pj; f[ipj]=(f[i]+f[i/u[i]]*u[i*pj])%mo; p[ipj]=(p[i]+p[i/u[i]]*(pj+1)%mo*u[ipj]%mo*u[i]%mo)%mo; miu[ipj]=0; break; } f[ipj]=f[i]*f[pj]%mo; p[ipj]=p[i]*p[pj]%mo; u[ipj]=pj; miu[ipj]=-miu[i]; } } for(int i=1;i<=nn;i++) p[i]=p[i]*i%mo; for(int i=1;i<=nn;i++) p[i]=(p[i]+p[i-1])%mo; for(int i=1;i<=nn;i++) g[i]=(g[i-1]+f[i])%mo; for(int i=1;i<=nn;i++) h[i]=g[i]*i%mo*f[i]%mo; for(int i=1;i<=nn;i++) miu[i]=(miu[i]*i*i%mo+mo)%mo; for(int i=1;i<=nn;i++) c[i]=(int)miu[i]; for(int i=1;i<=nn;i++) hh[i]=(int)h[i]; for(int i=1;i<=nn;i++) for(int k=i;k<=nn;k+=i) ans[k]=(ans[k]+(LL)hh[k/i]*c[i]%mo)%mo; for(int i=1;i<=nn;i++) ans[i]=(ans[i-1]+ans[i])%mo; scanf("%d",&T); for(int i=1;i<=T;i++) { read(n); int tu=(2*ans[n]%mo-p[n]+mo)%mo; printf("Case #%d: %d\n",i,tu); } return 0;}
阅读全文