之前寫過一發…然後這次作爲複習又重新寫了一遍
然後發現比上一次快了2000+ms??儘管依然很慢 。我好像沒加什麼優化啊(
(許是loj評測機性能變佳…..。?
做法
洲閣篩模板。代碼裏有詳細的註釋。
代碼
=> 注意初始化 //並不針對這道題,這題不初始化也沒事因爲只有一組數據,但是假如有多組或使用了多次cal的情況就要注意
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define per(i,x,y) for (int i=(x); i>=(y); i--)
#define ll long long
#define ld long double
#define inf 1000000000
using namespace std;
#define N 350005
int p[N/10],tot,res[N]; bitset<N> vis; ll n;
void pre(int n){
rep (i,2,n){
res[i]=res[i-1]; if (!vis[i]) p[++tot]=i,res[i]++;
for (int j=1; j<=tot && (ll)i*p[j]<=n; j++){
vis[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
}
#define M 350005
int sn,pos,cnt,last[M<<1]; ll g[M<<1],value[M<<1];
ll cal(ll n){//洲閣篩
cnt=0; sn=(ll)sqrt((ld)n);//考慮<=n的數由<=sqrtn的質數篩出的情況
pos=upper_bound(p+1,p+1+tot,sn)-p-1;//pos第一個小於等於sn的質數位置
for (ll i=n; i>=1; i=n/(n/i+1)) value[++cnt]=n/i;//記錄所有[n/i]的值,只有這樣的數纔會出現在轉移中 //離散
//g[i][j]表示1~j中與前i個質數互質的數的個數 //篩不掉的
//g[i][j]=g[i-1][j]-g[i-1][j/p[i]]
//當p[i+1]>j時,g[i][j]=1 //只有1
//p[i]>j/p[i]時,g[i][j]=g[i-1][j]-1,可以O(1)計算
ll k;
rep (i,1,cnt) g[i]=value[i],last[i]=0;//注意初始化last[i]=0
rep (i,1,pos) per (j,cnt,1){
k=value[j]/p[i]; if (k<p[i]) break;//忽略那些-1的轉移
k=k<sn?k:cnt-n/k+1;//找到在value中的對應下標
g[j]-=g[k]-(i-last[k]-1);//將g[k]的-1的轉移補回去
last[j]=i;
}
return res[sn]+g[cnt]-1;//-1是減去1的貢獻
}
//#define local
int main(){
#ifdef local
freopen("test.in","r",stdin); freopen("test.out","w",stdout);
#endif
pre(350000); cin>>n; cout<<cal(n)<<endl;
return 0;
}