2019ICPC南昌網絡賽-- Enju With math problem(素數間隔與歐拉函數性質)

一.題目及背景

與華工院賽一道題很像,那題ME的題解鏈接

題目鏈接

題目已經保證是連續的歐拉函數

 

二.性質

①10^9的最大素數間隔爲300

②積性函數性質,均爲素數,\varphi (p*q)=\varphi (p)*\varphi (q)

 

三.分析

①由於區間只有100<300,可能裏面沒有素數

②先假設有素數,那就是華工那道題的方法,暴力判斷p歐拉函數是否=p-1,見上面鏈接

如果全爲合數,將其拆分成p*q,q爲一個小素數,只要使得p素數間隔小於100肯定存在一個素數在此區間內。

接下來同①方法判斷即可。

 

經過下面代碼驗證,q只需取到7,素數間隔即小於100

(增刪條件即可)驗證代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e8 + 5e7;
bool np[MAXN + 5];
bool _2p[MAXN + 5], _3p[MAXN + 5];
bool _5p[MAXN + 5], _7p[MAXN + 5];
bool _11p[MAXN + 5], _17p[MAXN + 5];
int p[8444396 + 5], ptop;
void sieve() {
    np[1] = 1;
    ptop = 0;
    for(int i = 2; i <= MAXN; ++i) {
        if(!np[i]) {
            p[++ptop] = i;
        }
        for(int j = 1; j <= ptop; ++j) {
            ll t = i * p[j];
            if(t > MAXN)
                break;
            np[t] = 1;
            if(i % p[j] == 0)
                break;
        }
    }
    //printf("ptop=%d\n",ptop);
    for(int i = 1; i <= ptop; ++i) {
        if(2ll * p[i] > MAXN)
            break;
        _2p[p[i] * 2] = 1;
    }
    for(int i = 1; i <= ptop; ++i) {
        if(3ll * p[i] > MAXN)
            break;
        _3p[p[i] * 3] = 1;
    }
    for(int i = 1; i <= ptop; ++i) {
        if(5ll * p[i] > MAXN)
            break;
        _5p[p[i] * 5] = 1;
    }
    for(int i = 1; i <= ptop; ++i) {
        if(7ll * p[i] > MAXN)
            break;
        _7p[p[i] * 7] = 1;
    }
    for(int i = 1; i <= ptop; ++i) {
        if(11ll * p[i] > MAXN)
            break;
        _11p[p[i] * 11] = 1;
    }
    for(int i = 1; i <= ptop; ++i) {
        if(17ll * p[i] > MAXN)
            break;
        _17p[p[i] * 17] = 1;
    }
    int maxdis = 0, pre = 2;
    for(int i = 3; i <= MAXN; ++i) {
        if((!np[i]) || _2p[i] || _3p[i] || _5p[i] || _7p[i] || _11p[i] || _17p[i]) {
            maxdis = max(maxdis, i - pre);
            pre = i;
        }
    }
    printf("maxdis=%d\n", maxdis);
}

int main() {
    sieve();

    return 0;
}

 

四.代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105;
int prime[10] = {0, 2, 3, 5, 7, 11, 13,17};
//實際上到7就夠用了

//Miller-Rabin模板
    ll mul(ll a, ll b, ll p) {
        a %= p, b %= p;
        ll ans = 0;
        while(b) {
            if(b & 1) {
                ans = ans + a;
                if(ans > p) ans -= p;
            }
            a = a + a;
            if(a > p) a -= p;
            b >>= 1;
        }
        return ans;
    }
    ll qp(ll a, ll b, ll p) {
        ll ans = 1; a %= p;
        while(b) {
            if(b & 1) ans = mul(ans, a, p);
            a = mul(a, a, p);
            b >>= 1;
        }
        return ans;
    }

    bool check(ll a, ll n, ll x, ll t) {
        ll ans = qp(a, x, n);
        ll last = ans;
        for(int i = 1; i <= t; i++) {
            ans = mul(ans, ans, n);
            if(ans == 1 && last != 1 && last != n - 1) return true;
            last = ans;
        }
        if(ans != 1) return true;
        return false;
    }
    bool Miller_Rabin(ll n) {
        if(n == 1 || (n & 1) == 0) return false;
        if(n == 2) return true;
        ll x = n - 1, t = 0;
        while((x & 1) == 0) {x >>= 1, ++t;}
        srand(time(NULL));
        for(int i = 0; i < 8; i++) {
            ll a = rand() % (n - 1) + 1;
            if(check(a, n, x, t)) return false;
        }
        return true;
    }

//Miller-Rabin--end--

int T, n;
int a[N];

//遞歸求歐拉函數值
int getphi(int x) {
    int ans = x;
    for(int i = 2; 1ll * i * i <= x; i++) {
        if(x % i == 0) {
            ans = ans / i * (i - 1);
            while(x % i == 0) x /= i;
        }
    }
    if(x > 1) ans = ans / x * (x - 1);
    return ans;
}

//區間沒有素數的話,將合數拆成小素數*大素數
int f2() {
    int p = -1;
    for(int i = 1; i <= 6; i++) {
        for(int j = 1; j <= n; j++) {
            if(a[j] % (prime[i] - 1)) continue;
            int tmp = a[j] / (prime[i] - 1) + 1;
            if(Miller_Rabin(tmp)) {
                p = 1ll * tmp * prime[i] + 1 - j;
                int f = 1;
                for(int k = 1; k <= n; k++) {
                    if(a[k] != getphi(k + p - 1)) {
                        f = 0; break;
                    }
                }
                if(f) {
                    
                    return p;
                }
            }
        }
       
    }
   
    return -1;
}

//先假設裏面有素數
int f1() {
    int p = -1;
    for(int i = 1; i <= n; i++) {
        if(Miller_Rabin(a[i] + 1)) {
            p = a[i] + 2 - i;
            int f = 1;
            for(int j = 1; j <= n; j++) {
                if(a[j] != getphi(p + j - 1)) {
                    f = 0; break;
                }
            }
            if(f) {

                return p;
            }
        }
    }
    return f2();
//沒有素數的話,拆成兩個素數乘積
}



int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T; 
    n = 100;
    while(T--) {
        for(int i = 1; i <= n; i++) cin >> a[i];
        int ans = f1();
       if(ans!=-1)cout << "YES" << endl << ans << endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章