【題解】洛谷T48568[提高測試TG4]B.yyy送禮物 線性篩
阿新 • • 發佈:2018-12-13
簡單推導一下,可得每一項 的答案為 記數列 做差得遞推式 思考一下,發現減去的那一坨就是 的因子和減去 ,於是可以線性遞推了。 因子和可以線性篩方便求出。 (好像做麻煩了……)
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=1e7+10; ll ans[N]; int prime[N/10],p,sum[N]; bool iscomp[N]; int read() { int s=0,t=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')t=-1;ch=getchar();} while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar(); return s*t; } int t,n; ll qpow(ll a,int b) { ll ret=1; for(;b;b>>=1) { if(b&1)ret*=a; a*=a; } return ret; } void primetable() { sum[1]=1; for(int i=2;i<N;i++) { if(!iscomp[i])prime[p++]=i,sum[i]=1+i; for(int j=0;j<p&&i*prime[j]<N;j++) { iscomp[i*prime[j]]=1; if(i%prime[j]==0) { int tmp=i,f=1; while(tmp%prime[j]==0)tmp/=prime[j],f++; sum[i*prime[j]]=sum[tmp]*(qpow(prime[j],f+1)-1)/(prime[j]-1); break; } sum[i*prime[j]]=sum[i]*sum[prime[j]]; } } } int main() { primetable(); for(int i=2;i<N;i++) ans[i]=0ll+ans[i-1]+i-1-(sum[i]-i); t=read(); while(t--) { n=read(); printf("%lld\n",ans[n]); } return 0; }
總結
挺好的推公式題。線性篩確實可以輕鬆解決不少問題。