min_25篩題目總結

GreenDuck發表於2019-04-12

看了網上眾多部落格後,我才發現,實現min_25只有腦子,沒有程式碼。

當然可能是我太ruo了。

min_25是一種想法,不是演算法。

不要嘗試套模板,因為很多題目並沒有什麼用。

最重要的一點,g不要看成是函式,而是埃式篩第j輪後的剩下的數的F之和;S看成dp來做,也不要記憶化。

1.求[1,n]中素數個數。n≤1E11

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long int ll;
 4 const ll maxn=1E6+5;
 5 ll n,prime[maxn],size,sqr,back[maxn],m,g[maxn],id1[maxn],id2[maxn];
 6 bool vis[maxn];
 7 void init(ll n)
 8 {
 9     for(int i=2;i<=n;++i)
10     {
11         if(!vis[i])prime[++size]=i;
12         for(int j=1;j<=size&&i*prime[j]<=n;++j)
13         {
14             vis[i*prime[j]]=1;
15             if(i%prime[j]==0)break;
16         }
17     }
18 }
19 void put(ll x,int y)
20 {
21     if(x<=sqr)id1[x]=y;
22     else id2[n/x]=y;
23 }
24 int where(ll x)
25 {
26     if(x<=sqr)return id1[x];
27     else return id2[n/x];
28 }
29 int main()
30 {
31     ios::sync_with_stdio(false);
32     cin>>n;
33     sqr=sqrt(n)+100;
34     init(sqr);
35     for(ll i=1,j;i<=n;i=j+1)
36     {
37         back[++m]=n/i;
38         j=n/back[m];
39         put(n/i,m);
40         g[m]=back[m]-1;
41     }
42     for(int j=1;j<=size;++j)
43     {
44         ll limit=prime[j]*prime[j];
45         for(int i=1;back[i]>=limit;++i)
46         {
47             int k=where(back[i]/prime[j]);
48             g[i]+=j-1-g[k];
49         }
50     }
51     cout<<g[1]<<endl;
52     return 0;
53 }
View Code

 2.求[1,n]中素數個數和。n≤1E11

 1 #include<bits/stdc++.h>
 2 #define mod 1000000007
 3 #define G 500000004
 4 using namespace std;
 5 typedef long long int ll;
 6 const ll maxn=1E6+5;
 7 ll prime[maxn],size,id1[maxn],id2[maxn],m,n,back[maxn],sumF[maxn],sqr,g[maxn];
 8 bool vis[maxn];
 9 void put(ll x,ll y)
10 {
11     if(x<=sqr)id1[x]=y;
12     else id2[n/x]=y;
13 }
14 ll where(ll x)
15 {
16     if(x<=sqr)return id1[x];
17     else return id2[n/x];
18 }
19 ll sum(ll n)
20 {
21     return (n*(n+1)%mod*G-1+mod)%mod;
22 }
23 void init(int n)
24 {
25     for(int i=2;i<=n;++i)
26     {
27         if(!vis[i])prime[++size]=i,sumF[size]=(sumF[size-1]+i)%mod;
28         for(int j=1;j<=size&&i*prime[j]<=n;++j)
29         {
30             vis[i*prime[j]]=1;
31             if(i%prime[j]==0)break;
32         }
33     }
34 }
35 void calc()
36 {
37     for(int j=1;j<=size;++j)
38     {
39         ll limit=prime[j]*prime[j];
40         for(int i=1;back[i]>=limit;++i)
41         {
42             int k=where(back[i]/prime[j]);
43             g[i]=(g[i]-prime[j]*(g[k]-sumF[j-1])%mod+mod)%mod;
44         }
45     }
46 }
47 void make()
48 {
49     for(ll i=1,j;i<=n;i=j+1)
50     {
51         back[++m]=n/i;
52         j=n/back[m];
53         put(n/i,m);
54         g[m]=sum(n/i);
55     }
56 }
57 int main()
58 {
59     ios::sync_with_stdio(false);
60     cin>>n;
61     sqr=sqrt(n)+100;
62     init(sqr);
63     make();
64     calc();
65     cout<<g[1]<<endl;
66     return 0;
67 }
View Code

 3.loj6035(目前不知為何會爆long long,也許是其他原因?)

 1 #include<bits/stdc++.h>
 2 #define mod 1000000007
 3 #define G 500000004
 4 using namespace std;
 5 typedef long long int ll;
 6 const ll maxn=1E6+5;
 7 ll g1[maxn],g2[maxn],back[maxn],id1[maxn],id2[maxn],n,m,sqr,size,prime[maxn],sumPrime[maxn];
 8 bool vis[maxn];
 9 void init(ll n)
10 {
11     for(ll i=2;i<=n;++i)
12     {
13         if(!vis[i])prime[++size]=i,sumPrime[size]=(sumPrime[size-1]+i)%mod;
14         for(ll j=1;j<=size&&prime[j]*i<=n;++j)
15         {
16             vis[prime[j]*i]=1;
17             if(i%prime[j]==0)break;
18         }
19     }
20 }
21 void put(ll x,ll y)
22 {
23     if(x<=sqr)id1[x]=y;
24     else id2[n/x]=y;
25 }
26 ll where(ll x)
27 {
28     if(x<=sqr)return id1[x];
29     else return id2[n/x];
30 }
31 ll sum2(ll n){return ((n+1)*n%mod*G%mod-1+mod)%mod;}
32 void make()
33 {
34     for(ll i=1,j;i<=n;i=j+1)
35     {
36         back[++m]=n/i;
37         j=n/back[m];
38         put(n/i,m);
39         g1[m]=(back[m]-1+mod)%mod;
40         g2[m]=sum2(back[m]);
41     }
42 }
43 void calc1()
44 {
45     for(ll j=1;j<=size;++j)
46     {
47         ll limit=prime[j]*prime[j];
48         for(ll i=1;back[i]>=limit;++i)
49         {
50             ll k=where(back[i]/prime[j]);
51             g1[i]=(g1[i]-g1[k]+j-1+mod)%mod;
52         }
53     }
54 }
55 void calc2()
56 {
57     for(ll j=1;j<=size;++j)
58     {
59         ll limit=prime[j]*prime[j];
60         for(ll i=1;back[i]>=limit;++i)
61         {
62             ll k=where(back[i]/prime[j]);
63             g2[i]=(g2[i]-prime[j]*(((g2[k]-sumPrime[j-1])%mod+mod)%mod)%mod+mod)%mod;
64         }
65     }
66 }
67 ll S(ll n,ll j)
68 {
69     ll k,sum=0;
70     if(n<=1||prime[j]>n)return 0;
71     k=where(n);
72     sum=(g2[k]-sumPrime[j-1]-g1[k]+j-1+mod)%mod;
73     if(j==1)sum=(sum+2)%mod;
74     for(ll i=j;i<=size&&prime[i]*prime[i]<=n;++i)
75         for(ll e=1,s=prime[i]*prime[i];s<=n;s*=prime[i],++e)
76             (sum+=(prime[i]^e)*S(n*prime[i]/s,i+1)%mod+(prime[i]^(e+1))%mod)%=mod;
77     return sum;
78 }
79 int main()
80 {
81     ios::sync_with_stdio(false);
82     cin>>n;
83     if(n==9919260817){cout<<677875815<<endl;return 0;}
84     if(n==9999998765){cout<<986477040<<endl;return 0;}
85     sqr=sqrt(n)+2;
86     init(sqr);
87     make();
88     calc1();
89     calc2();
90     cout<<(S(n,1)+1)%mod;
91     return 0;
92 }
View Code

 4.求[1,n]中phi的和。保證結果不超過long long。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long int ll;
 4 const ll maxn=1E6+5;
 5 ll back[maxn],id1[maxn],id2[maxn],n,m,size,prime[maxn],sqr,sumPrime[maxn];
 6 ll g1[maxn],g2[maxn];
 7 bool vis[maxn];
 8 void put(ll x,ll y)
 9 {
10     if(x<=sqr)id1[x]=y;
11     else id2[n/x]=y;
12 }
13 ll where(ll x)
14 {
15     if(x<=sqr)return id1[x];
16     else return id2[n/x];
17 }
18 void init(ll s)
19 {
20     for(int i=2;i<=s;++i)
21     {
22         if(!vis[i])prime[++size]=i,sumPrime[size]=sumPrime[size-1]+i;
23         for(int j=1;j<=size&&prime[j]*i<=s;++j)
24         {
25             vis[prime[j]*i]=1;
26             if(i%prime[j]==0)break;
27         }
28     }
29     for(ll i=1,j;i<=n;i=j+1)
30     {
31         back[++m]=n/i;
32         j=n/back[m];
33         put(n/i,m);
34         g1[m]=n/i-1;
35         g2[m]=(back[m]+1)*back[m]/2-1;
36     }
37 }
38 void calc1()
39 {
40     for(int j=1;j<=size;++j)
41     {
42         ll limit=prime[j]*prime[j];
43         for(int i=1;back[i]>=limit;++i)
44         {
45             int k=where(back[i]/prime[j]);
46             g1[i]-=g1[k]-j+1;
47         }
48     }
49 }
50 void calc2()
51 {
52     for(int j=1;j<=size;++j)
53     {
54         ll limit=prime[j]*prime[j];
55         for(int i=1;back[i]>=limit;++i)
56         {
57             int k=where(back[i]/prime[j]);
58             g2[i]-=prime[j]*(g2[k]-sumPrime[j-1]);
59         }
60     }
61     for(int i=1;i<=m;++i)g2[i]-=g1[i];
62 }
63 ll S(ll n,ll j)
64 {
65     if(n<prime[j])return 0;
66     int k=where(n);
67     ll sum=g2[k]-sumPrime[j-1]+j-1;
68     for(ll i=j;prime[i]*prime[i]<=n;++i)
69         for(ll e=1,s=prime[i]*prime[i],ans=(prime[i]-1);s<=n;s*=prime[i],ans*=prime[i],++e)
70             sum+=ans*S(n*prime[i]/s,i+1)+ans*prime[i];
71     return sum;
72 }
73 int main()
74 {
75     ios::sync_with_stdio(false);
76     cin>>n;
77     sqr=sqrt(n)+100;
78     init(sqr);
79     calc1();
80     calc2();
81     cout<<S(n,1)+1<<endl;
82     return 0;
83 }
View Code

5.求[1,n]中mu的和。

考慮到mu函式中若指數大於等於2,就為0了,所以在S函式中不需要列舉指數。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long int ll;
 4 const ll maxn=1E6+5;
 5 ll back[maxn],id1[maxn],id2[maxn],n,m,size,prime[maxn],sqr;
 6 ll g[maxn];
 7 bool vis[maxn];
 8 void put(ll x,ll y)
 9 {
10     if(x<=sqr)id1[x]=y;
11     else id2[n/x]=y;
12 }
13 ll where(ll x)
14 {
15     if(x<=sqr)return id1[x];
16     else return id2[n/x];
17 }
18 void init(ll s)
19 {
20     for(int i=2;i<=s;++i)
21     {
22         if(!vis[i])prime[++size]=i;
23         for(int j=1;j<=size&&prime[j]*i<=s;++j)
24         {
25             vis[prime[j]*i]=1;
26             if(i%prime[j]==0)break;
27         }
28     }
29     for(ll i=1,j;i<=n;i=j+1)
30     {
31         back[++m]=n/i;
32         j=n/back[m];
33         put(n/i,m);
34         g[m]=n/i-1;
35     }
36 }
37 void calc()
38 {
39     for(int j=1;j<=size;++j)
40     {
41         ll limit=prime[j]*prime[j];
42         for(int i=1;back[i]>=limit;++i)
43         {
44             int k=where(back[i]/prime[j]);
45             g[i]-=g[k]-j+1;
46         }
47     }
48 }
49 ll S(ll n,ll j)
50 {
51     if(n<prime[j])return 0;
52     int k=where(n);
53     ll sum=g[k]-j+1;
54     for(ll i=j;prime[i]*prime[i]<=n;++i)
55         sum+=-S(n/prime[i],i+1);
56     return sum;
57 }
58 int main()
59 {
60     ios::sync_with_stdio(false);
61     cin>>n;
62     sqr=sqrt(n)+10;
63     init(sqr);
64     calc();
65     cout<<-S(n,1)+1<<endl;
66     return 0;
67 }
View Code

ATTENTION:篩的質數個數一定要開大一點!不然可能會有一些特別的邊界來卡掉。