推式子:https://www.cnblogs.com/cjoieryl/p/10150718.html
又学习了一下杜教筛hh;
原来 unsigned int 的输出是 %u 啊;
注意各处还是要用 (ll),不要不小心都写成 (uint) 了;
然而递归版很慢...
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef unsigned int uint; typedef long long ll; int const xn=1e6+5; int n,m,K,pri[xn],cnt,w[xn],sqr; uint prk[xn],h[xn],G[xn]; bool vis[xn]; uint pw(uint a,int b){uint ret=1; for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a; return ret;} void init(int mx) { for(int i=2;i<=mx;i++) { if(!vis[i])pri[++cnt]=i,prk[cnt]=pw(i,K); for(int j=1;j<=cnt&&(ll)i*pri[j]<=mx;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0)break; } } } int Id(int x) { if(x>sqr)return n/x; return m-x+1; } uint F(int x,int y) { if(pri[y]>x)return 0; uint ret=0; for(int i=y;i<=cnt&&(ll)pri[i]*pri[i]<=x;i++)//ll for(ll p0=pri[i];p0*pri[i]<=x;p0*=pri[i]) ret+=F(x/p0,i+1)+(uint)prk[i]*(h[Id(x/p0)]-i+1); return ret; } uint S(int x) { if(G[Id(x)]!=-1)return G[Id(x)]; uint ret=F(x,1)+h[Id(x)]; for(int i=2,j;i<=x;i=j+1)j=x/(x/i),ret-=(j-i+1)*S(x/i); return G[Id(x)]=ret; } int main() { scanf("%d%d",&n,&K); sqr=sqrt(n); init(sqr); for(int i=1,j;i<=n;i=j+1) {w[++m]=n/i; j=n/w[m]; h[m]=w[m]-1;} for(int j=1;j<=cnt;j++) for(int i=1;i<=m&&(ll)pri[j]*pri[j]<=w[i];i++) h[i]=h[i]-h[Id(w[i]/pri[j])]+j-1;//w[i] memset(G,-1,sizeof G); uint ans=0; for(int T=1,nxt;T<=n;T=nxt+1) { nxt=n/(n/T); ans+=(uint)(n/T)*(n/T)*(S(nxt)-S(T-1)); } printf("%u ",ans);// return 0; }
于是写成了循环版,真的变快了^_^
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef unsigned int uint; typedef long long ll; int const xn=1e6+5; int n,m,K,pri[xn],cnt,w[xn],sqr; uint prk[xn],h[xn],G[xn],f[xn]; bool vis[xn]; uint pw(uint a,int b){uint ret=1; for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a; return ret;} void init(int mx) { for(int i=2;i<=mx;i++) { if(!vis[i])pri[++cnt]=i,prk[cnt]=pw(i,K); for(int j=1;j<=cnt&&(ll)i*pri[j]<=mx;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0)break; } } } int Id(int x) { if(x>sqr)return n/x; return m-x+1; } void getf() { for(int i=cnt;i;i--) for(int j=1;j<=m&&(ll)pri[i]*pri[i]<=w[j];j++) for(ll p0=pri[i];p0*pri[i]<=w[j];p0*=pri[i]) f[j]+=f[Id(w[j]/p0)]+(uint)prk[i]*(h[Id(w[j]/p0)]-i+1); } uint S(int x) { if(G[Id(x)]!=-1)return G[Id(x)]; uint ret=f[Id(x)]+h[Id(x)]; for(int i=2,j;i<=x;i=j+1)j=x/(x/i),ret-=(j-i+1)*S(x/i); return G[Id(x)]=ret; } int main() { scanf("%d%d",&n,&K); sqr=sqrt(n); init(sqr); for(int i=1,j;i<=n;i=j+1) {w[++m]=n/i; j=n/w[m]; h[m]=w[m]-1;} for(int j=1;j<=cnt;j++) for(int i=1;i<=m&&(ll)pri[j]*pri[j]<=w[i];i++) h[i]=h[i]-h[Id(w[i]/pri[j])]+j-1;//w[i] memset(G,-1,sizeof G); uint ans=0; getf(); for(int T=1,nxt;T<=n;T=nxt+1) { nxt=n/(n/T); ans+=(uint)(n/T)*(n/T)*(S(nxt)-S(T-1)); } printf("%u ",ans);// return 0; }