2019华南理工大学“三七互娱杯”程序设计竞赛F HRY and ec-final--素数间隔与欧拉函数

一.背景

题目链接

 补这题,是因为昨天网络赛碰到一道素数间隔的题(非常相似,但是作法有差异)

 

二.重要性质:

①10^9的最大素数间隔为300

\varphi (p)=p-1(p为素数)

 

三.思路

这题数据范围是1e9,而且给出区间是300,根据素数间隔规律,区间里必有一个素数,只要看该素数的欧拉函数值是否对应即可,有两种方法:

a.按顺序找,直到符合为止(本代码方法)

b.找欧拉函数区间里最大的那个数,那个数一定是素数,同上判断是否符合。

因为根据欧拉函数定义,小于n的数中与n互质的数的数目,显然小范围内合数欧拉函数比质数小

 

b方法见链接

 

四.代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 315;

namespace 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 go(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;
    }
}

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;
}

bool gao1() {
    int p = -1;
    for(int i = 1; i <= n; i++) {
        if(Miller_Rabin::go(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)||(a[j]+300-j)>1e9) 
                    //右边必须加个条件防止跳出范围
                {
                    f = 0; break;
                }
            }
            if(f) {
                cout <<  p << '\n';
                return true;
            }
        }
    }
    cout << "yang12138 laji" << '\n';
    return false;
}

const int prime[10] = {0, 2, 3, 5, 7, 11, 13};
void gao2() {
    int p = -1;
    for(int i = 1; i <= 4; 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::go(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) {
                    cout << p << '\n';
                    return;
                }
            }
        }
    }
    cout << "yang12138 laji" << '\n';
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    //cin >> T;
    T=1;
    n = 300;
    while(T--) {
        for(int i = 1; i <= n; i++) cin >> a[i];
        bool f = gao1();
        //if(!f) gao2();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值