HDU 2619 - Love you Ten thousand years (原根)

本文探讨了在数学领域中,如何通过计算特定数值的原根数量来象征性地表达爱意。原根,作为模意义下的一类特殊整数,其数量与一个奇素数的欧拉函数值紧密相关。通过对欧拉函数的深入理解,我们能够计算出一个给定奇素数的原根数量,进而寓意为爱的天数。文章提供了详细的算法实现,包括欧拉函数的计算方法和原根判断过程。

Description:

Love you Ten thousand years------Earth’s rotation is a day that is the representative of a day I love you. True love, there is no limit and no defects. Earth’s revolution once a year, it is on behalf of my love you more than a year. Permanent horizon, and my heart will never change ……

We say that integer x,0<x<n,x, 0 < x < n,x,0<x<n,(nnn is a odd prime number) is a LovePoint-based-on n if and only if the set (ximodn)∣1<=i<=n−1{ (x i mod n) | 1 <= i <= n-1 }(ximodn)1<=i<=n1 is equal to 1,...,n−1{ 1, ..., n-1 }1,...,n1. For example, the powers of 333 modulo 777 are 3,2,6,4,5,13, 2, 6, 4, 5, 13,2,6,4,5,1, and thus 333 is a LovePoint-based-on 777.
Now give you a integer n>=3n >= 3n>=3(nnn will not exceed 2312 31231).
We say the number of LovePoint-based-on n is the number of days the earth rotating.
Your task is to calculate the number of days someone loved you.

Input

Each line of the input contains an integer nnn. Input is terminated by the end-of-file.

Output

For each nnn, print a single number that gives the number of days someone loved you.

Sample Input

5

Sample Output

2

求有多少i(<=n−1)i(<=n-1)i(<=n1),使 ximod  nx^i \mod nximodn 的值为 [1,n−1][1,n-1][1,n1],其实也就是满足完全剩余类的原根数量。

m>1m > 1m>1gcd(a,m)=1gcd(a, m) = 1gcd(a,m)=1, 则使得 at≡1(modm)a^t ≡ 1(mod m)at1(modm) 成立的最小的正整数 ttt 称为 aaa 对模mmm的阶, 记为δm(a)δm(a)δm(a)

如果 aaa的阶(modm)(mod m)(modm)ϕ(m)ϕ(m)ϕ(m), 则称 aaammm 的一个原根。 即若 δm(a)=ϕ(m)δm(a)=ϕ(m)δm(a)=ϕ(m), 则称aaammm 的一个原根。

定理1:若 gggmmm 的一个原根,则 g,g2,⋯,gϕ(m)g,g^2,⋯,g^ϕ(m)g,g2,,gϕ(m)

各数对模 mmm 的最小剩余,恰是小于 mmm 且与 mmm 互素的 ϕ(m)ϕ(m)ϕ(m) 个正整数的一个排列。

定理2:每一个素数 ppp 都有 ϕ(p−1)ϕ(p−1)ϕ(p1) 个原根。ϕ(m)ϕ(m)ϕ(m) 为小于mmm 的素数的个数,事实上, 每一个数 mmm 都有 ϕ(ϕ(m))ϕ(ϕ(m))ϕ(ϕ(m)) 个原根(如果有的话)。即 若 nnn 为素数 ϕ(p−1)=ϕ(ϕ(p))ϕ(p−1) = ϕ(ϕ(p))ϕ(p1)=ϕ(ϕ(p))

这个题中 nnn 为奇素数,故形成的为完全剩余系。求 nnn 的原根数量即可。

AC代码:

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stack>
#include <queue>
using namespace std;
#define sd(n) scanf("%d", &n)
#define sdd(n, m) scanf("%d%d", &n, &m)
#define sddd(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define pd(n) printf("%d\n", n)
#define pc(n) printf("%c", n)
#define pdd(n, m) printf("%d %d", n, m)
#define pld(n) printf("%lld\n", n)
#define pldd(n, m) printf("%lld %lld\n", n, m)
#define sld(n) scanf("%lld", &n)
#define sldd(n, m) scanf("%lld%lld", &n, &m)
#define slddd(n, m, k) scanf("%lld%lld%lld", &n, &m, &k)
#define sf(n) scanf("%lf", &n)
#define sc(n) scanf("%c", &n)
#define sff(n, m) scanf("%lf%lf", &n, &m)
#define sfff(n, m, k) scanf("%lf%lf%lf", &n, &m, &k)
#define ss(str) scanf("%s", str)
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define mem(a, n) memset(a, n, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
#define mod(x) ((x) % MOD)
#define gcd(a, b) __gcd(a, b)
#define lowbit(x) (x & -x)
typedef pair<int, int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
inline int read()
{
    int ret = 0, sgn = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            sgn = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = getchar();
    }
    return ret * sgn;
}
inline void Out(int a)
{
    if (a > 9)
        Out(a / 10);
    putchar(a % 10 + '0');
}

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b)
{
    return a * b / gcd(a, b);
}
///快速幂m^k%mod
ll qpow(int m, int k, int mod)
{
    ll res = 1, t = m;
    while (k)
    {
        if (k & 1)
            res = res * t % mod;
        t = t * t % mod;
        k >>= 1;
    }
    return res;
}

// 快速幂求逆元
int Fermat(int a, int p) //费马求a关于b的逆元
{
    return qpow(a, p - 2, p);
}

///扩展欧几里得
int exgcd(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int g = exgcd(b, a % b, x, y);
    int t = x;
    x = y;
    y = t - a / b * y;
    return g;
}

///使用ecgcd求a的逆元x
int mod_reverse(int a, int p)
{
    int d, x, y;
    d = exgcd(a, p, x, y);
    if (d == 1)
        return (x % p + p) % p;
    else
        return -1;
}

///中国剩余定理模板
ll china(int a[], int b[], int n) //a[]为除数,b[]为余数
{
    int M = 1, y, x = 0;
    for (int i = 0; i < n; ++i) //算出它们累乘的结果
        M *= a[i];
    for (int i = 0; i < n; ++i)
    {
        int w = M / a[i];
        int tx = 0;
        int t = exgcd(w, a[i], tx, y); //计算逆元
        x = (x + w * (b[i] / t) * x) % M;
    }
    return (x + M) % M;
}

ll phi(ll n)
{
    ll ans = n;
    for (int i = 2; i * i <= n; i++)
    {
        if (n % i == 0)
        {
            ans -= ans / i;//素数倍数的个数减去
            while (n % i == 0)
                n /= i;//除去素数倍数
        }
    }
    if (n > 1)//对素数特判
        ans -= ans / n;
    return ans;
}//互素数的个数

ll n, m;
int main()
{
    while (~sld(n))
    {
        pld(phi(phi(n)));
    }
    return 0;
}




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值