這題實在是比較一棵賽艇就發上來好了。
題目:
給定n,求出小於等於n的所有合數的最小質因數之和。
對於70%的數據,n<=10^7。
對於100%的數據,n<=10^9。
題解:
70% 線篩大法好
100%
首先我們考慮對於每一個小於等於sqrt(n)的質數容斥,然后稍微推一推就可以得到一個比較靠譜的容斥方法,雖然復雜度玄學但是似乎跑得蠻快的。然后我們測一下時間……真是不巧n=10^9要跑2s左右。(我就是這么被卡掉的
標程是這樣的:
我們定一個閥值k=100,對於<=k的質因數(一共也就才幾十個)我們用科學的容斥搞一搞,這個復雜度基本沒有。
對於>=k的質因數p我們可以發現n/p是在10^7以內的。然后為了保證質因數是最小的,我們必須只能選n不是<p質數的倍數的。那么我們發現n/p顯然也要不是<p質數的倍數。
這樣我們用一個暴力篩法來維護n/p,具體做法是因為p遞增時n/p遞減,那么我們考慮線篩的上界也是遞減的,每次線篩賦值bool數組的時候順便更新一下答案,減小上界的時候就把多的答案扣掉。既然1kw的暴力篩法可以過,這樣顯然是科學的。
n=10^9只要跑0.1s左右。事實上如果把k設成1000跑n=10^10也只要跑0.6s左右。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> #include <vector> #include <math.h> #include <time.h> #include <limits> #include <set> #include <map> using namespace std; int sq,n; #define FJ 100 //1000? #define ZS 10000005 bool yz[ZS+3]; int mn=ZS,cnt=0; bool isprime(int x) { for(int p=2;p*p<=x;p++) { if(x%p==0) return 0; } return 1; } int pn=0,ps[233333]; long long ans=0; void dfs(int x,int lst,int dep) { if(lst!=0) { ans+=n/x*(long long)ps[lst]*dep; if(x==ps[lst]) ans-=x; } for(int i=lst+1;i<=pn;i++) { if(ps[i]<=FJ&&(long long)x*ps[i]<=n) dfs(x*ps[i],i,-dep); else break; } } void xj(int p) { while(mn>p) cnt-=yz[mn--]; } void pj(int p) { for(int j=p;j<=mn;j+=p) { if(yz[j]) continue; yz[j]=1; ++cnt; } } #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} int main() { //FO(prime) scanf("%d",&n); sq=sqrt(n)+1; int cc=0; for(int i=2;i<=sq;i++) { if(isprime(i)) ps[++pn]=i; } dfs(1,0,-1); for(int i=1;i<=pn;i++) { int cur=ps[i]; if(cur>FJ) { xj(n/cur); ans+=(n/cur-cnt-1)*(long long)cur; } pj(cur); } printf("%lld\n",ans); }
嗯今天閆神還立了一個flag,說不會求質數的答案。那我們就是要求n以內質數的和。
丟鏈接跑 http://mathoverflow.net/questions/81443/fastest-algorithm-to-compute-the-sum-of-primes