1. 程式人生 > 其它 >Acwing 196.質數距離 197.階乘分解

Acwing 196.質數距離 197.階乘分解

196.質數距離

題目描述

給定兩個整數L和U,你需要在閉區間[L,U]內找到距離最接近的兩個相鄰質數C1和C2(即C2-C1是最小的),如果存在相同距離的其他相鄰質數對,則輸出第一對。

同時,你還需要找到距離最遠的兩個相鄰質數D1和D2(即D1-D2是最大的),如果存在相同距離的其他相鄰質數對,則輸出第一對。

輸入格式

每行輸入兩個整數L和U,其中L和U的差值不會超過1000000。

輸出格式
對於每個L和U ,輸出一個結果,結果佔一行。

結果包括距離最近的相鄰質數對和距離最遠的相鄰質數對。(具體格式參照樣例)

如果L和U之間不存在質數對,則輸出“There are no adjacent primes.”。

資料範圍

1≤L<U≤2^31−1

輸入樣例:

2 17
14 17

輸出樣例:

2,3 are closest, 7,11 are most distant.
There are no adjacent primes.

題目分析:由於L、R的範圍太大,所以我們不可能用線性篩法去求出所有的素數,然後比較;但是題目中還有一個資訊,那就是L到R的距離最多為10^6,而且我們知道一點:一個合數n一定存在一個小於等於√n的質因子,所以我們可以求出質因子p,然後根據質因子p找出[L,R]中所有的合數,那麼剩下的就是質數了。
現在問題是如何根據質因子p(對於質因子p,我們可以根據線性篩法找到[1,50000]中所有的質數,因為2^31開根號大約為50000)找出合數。

我們的目的是要找到p的倍數,首先先找到[L,R]中最小的p的倍數的數作為起點,設x>=L,x最小且x能被p整除,則x=floor(L/p)*p(floor指的是上取整),那麼轉化為下取整就是x=(L+p-1)/p*p(ceil()指的是下取整),已知起點遍歷即可,詳情看程式碼~
程式碼:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
#define N 1000010
bool vis[N];
long long int prime[N],cnt;
void Prime(int n)
{
    memset
(vis,false,sizeof(vis));//全部初始化為是素數 vis[0]=true; vis[1]=true; cnt=0; for(int i=2; i<=n; i++) { if(!vis[i]) prime[cnt++]=i; for(int j=0; j<cnt&&i*prime[j]<=n; j++) { vis[i*prime[j]]=true; if(i%prime[j]==0) { break; } } } } int main() { int l,r; while(cin>>l>>r) { Prime(50000); memset(vis,false,sizeof(vis));//重複利用vis陣列 for(int i=0; i<cnt; i++) { long long p=prime[i]; /*檢索[l,r]上p的倍數,並標記為合數,有可能會碰到l=1(l,r很小,p在l到r的範圍內)的情況,即j=p, 這樣就會誤把質數p標記為合數,所以要至少從2*p開始*/ for(long long int j=max(2*p,(l+p-1)/p*p); j<=r; j+=p) { vis[j-l]=true;//標記為合數,並離散化,因為l和r的範圍很大,有10的9次方級別,所以要進行離散化處理,否則會超陣列範圍 } } cnt=0;//重複利用cnt for(int i=0; i<=r-l; i++) { if(!vis[i]&&i+l>=2)//1即不是合數也不是質數,所以要特判 { prime[cnt++]=i+l; } } if(cnt<2) { cout<<"There are no adjacent primes."<<endl; } else { int maxx=0,minn=0; for(int i=0; i<cnt-1; i++) { int d=prime[i+1]-prime[i]; if(d>prime[maxx+1]-prime[maxx]) maxx=i; if(d<prime[minn+1]-prime[minn]) minn=i; } printf("%lld,%lld are closest, %lld,%lld are most distant.\n",prime[minn],prime[minn+1],prime[maxx],prime[maxx+1]); } } return 0; }

197. 階乘分解

題目描述

給定整數 N ,試把階乘 N! 分解質因數,按照算術基本定理的形式輸出分解結果中的 pi 和 ci 即可。

輸入格式

一個整數N。

輸出格式

N! 分解質因數後的結果,共若干行,每行一對pi,ci,表示含有pi和ci項。按照pi從小到大的順序輸出。

資料範圍
1≤N≤106

輸入樣例:

5

輸出樣例:

2 3
3 1
5 1
樣例解釋
5!=120=23∗3∗5

題目分析:首先找出1-n中所有的質數(線性篩法),1-n中所有質數必然全部都為n!的質因子。首先我們要先知道1-n中有多少個p(1-n中的質數)的倍數,1-n中有ceil(n/p)個p的倍數,每個p的倍數都至少存在一個p的指數次方,每個p的平方都至少存在兩個p的指數次方,每個p的三次方都至少存在三個p的指數次方…,所以p的ci等於在這裡插入圖片描述
(在計算ceil(n/p)時相當於漏算了一個p^2的指數次,兩個p ^3的指數次。。。)
程式碼:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
#define N 1000010
int vis[N];
int prime[N],cnt;
void Prime(int n)
{
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            prime[cnt++]=i;
        }
        for(int j=0;j<cnt&&i*prime[j]<=n;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                break;
            }
        }
    }
}
int main()
{
    int n;
    cin>>n;
    Prime(n);
    for(int i=0;i<cnt;i++)
    {
        int t=n,p=prime[i];
        int sum=0;
        while(t)
        {
            sum+=t/p;
            t/=p;//代替n/p,n/(p^2),n/(p^3)....
        }
        cout<<p<<" "<<sum<<endl;
    }
    return  0;
}