HDU - 4335 What is N?(扩展欧拉+指数循环节+细节处理)

传送门


首先根据欧拉降幂的公式得到 n n ! % φ ( p ) + φ ( p ) ( m o d    p ) n^{n!\% \varphi(p)+\varphi(p)}(mod~~p) nn!%φ(p)+φ(p)(mod  p),那么代码整体分三种情况考虑:

  • n ! < φ ( p ) n!<\varphi(p) n!<φ(p)时,暴力判断 i ! % p = = b i!\%p==b i!%p==b
  • φ ( p ) ! > n ! ≥ φ ( p ) \varphi(p)! > n! \geq \varphi(p) φ(p)!>n!φ(p)时,也需要暴力去判断 i ! % φ ( p ) + φ ( p ) = = b i!\%\varphi(p)+\varphi(p)==b i!%φ(p)+φ(p)==b
  • φ ( p ) ! ≤ n ! \varphi(p)! \leq n! φ(p)!n!,指数肯定是 0 + φ ( p ) = φ ( p ) 0+\varphi(p)=\varphi(p) 0+φ(p)=φ(p),也就是变成了求 x k ≡ b    ( m o d    p ) x^k \equiv b~~ (mod~~p) xkb  (mod  p),这个同余方程的求解还是涉及到了较深的知识点,网上没有博客讲,在知网有一些论文有兴趣可以看。因为 p p p不一定是素数且范围较小,打表可知 x k % p x^k\%p xk%p的循环节恰好为 p p p

注意当 p = 1 p=1 p=1时,如果 m = 2 64 − 1 m=2^{64}-1 m=2641,再加上 0 0 0恰好为 2 64 2^{64} 264爆范围,所以特判

//
// Created by Happig on 2020/8/26
//
#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define lowbit(x) (x&(-x))
#define mkp(x, y) make_pair(x,y)
#define mem(a, x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 2e5 + 10;

ull euler_phi(ull n) {
     
    int m = sqrt(n + 0.5);
    ull ans = n;
    for (int i = 2; i <= m; i++)
        if (n % i == 0) {
     
            ans = ans * (i - 1) / i;
            while (n % i == 0) n /= i;
        }
    if (n > 1) ans = ans * (n - 1) / n;
    return ans;
}

ull qkp(ull x, ull n, ull p) {
     
    ull ans = 1;
    x %= p;
    while (n) {
     
        if (n & 1) ans = ans * x % p;
        x = x * x % p;
        n >>= 1;
    }
    return ans;
}

int cnt[maxn];

int main() {
     
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t, kase = 0;
    ull b, p, m;
    cin >> t;
    while (t--) {
     
        cin >> b >> p >> m;
        cout << "Case #" << ++kase << ": ";
        if (p == 1) {
     
            if (m == 18446744073709551615ull)
                cout << "18446744073709551616\n";
            else cout << m + 1 << "\n";
            continue;
        }
        ull phi = euler_phi(p), cur = 1, ans = 0, l;
        if (b == 0) ans++;
        for (int i = 1; i <= m; i++) {
     
            cur *= i, l = i;
            if (cur >= phi) break;
            if (qkp(i, cur, p) == b) ans++;
        }
        if (cur < phi) {
     
            cout << ans << "\n";
            continue;
        }
        cur %= phi;
        if (qkp(l, cur + phi, p) == b) ans++;
        for (l = l + 1; l <= m; l++) {
     
            cur = (cur * l) % phi;
            if (cur == 0) break;
            if (qkp(l, cur + phi, p) == b) ans++;
        }
        if (l <= m) {
     
            ll num = 0;
            for (int i = 0; i < p; i++) {
     
                if (qkp(i + l, phi, p) == b) cnt[i] = 1, num++;
                else cnt[i] = 0;
            }
            ll k = (m - l + 1) / p;
            ans += num * k;
            ll res = (m - l + 1) % p;
            for (int i = 0; i < res; i++) ans += cnt[i];
        }
        cout << ans << "\n";
    }
    return 0;
}

你可能感兴趣的:(数论)