費馬大定理(原根+擴歐)

考慮方程x^k+y^k=z^k,其中x,y,z,k≠0 ,且均爲正整數。衆所周知,由費馬大定理,當k> 2時,方程無解。現在考慮在模意義下的問題。
給定一個質數P,以及一個正整數L,現在想知道有多少個整數k,滿足1<=k<=L,存在x,y,z,0<x,y,z<P,使得x^k+y^k≡z^k (mod P)

輸入

輸入兩個整數P,L。

輸出

輸出一個整數代表合法的k的個數

樣例輸入 Copy

3 10

樣例輸出 Copy

5

 

X^{k} + Y^{k} \equiv Z^{k}(mod P)

1 + (\frac{Y}{X}) ^{k} \equiv (\frac{Z}{X}) ^{k}(mod P)

(\frac{Z}{X}) ^{k} - (\frac{Y}{X}) ^{k} \equiv 1 (mod P)

考慮用P的原根root表示\frac{Z}{X} , \frac{Y}{X}

g^{ak} - g^{bk} \equiv 1 (mod P)

我們考慮找出滿足下麪條件的(t1, t2)對

g^{t1} - g^{t2} \equiv 1 (mod P)

那麼求解上面方程組的條件就是

ak \equiv t1 (mod P - 1)    bk \equiv t2 (mod P - 1)

考慮對於擴歐不定方程(裴蜀定理)時的條件,需要滿足(k, p - 1) | t1 以及 (k, p - 1) | t2

所以需滿足(k, p - 1) | (t1, t2)

然後直接枚舉即可

/**/
#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

LL n;
int p, tot, cnt;
int prim[78505], fa[205], a[1000005];
bool vis[1000005], b[1000005];

void get(){
	vis[1] = vis[0] = 1;
	for (int i = 2; i <= 1000000; i++){
		if(!vis[i]) prim[tot++] = i;
		for (int j = 0; j < tot && prim[j] * i <= 1000000; j++){
			int x = prim[j] * i;
			vis[x] = true;
			if(i % prim[j] == 0) break;
		}
	}
}

LL poww(LL x, LL num, LL mod){
	LL res = 1;
	while(num){
		if(num & 1) res = res * x % mod;
		x = x * x % mod;
		num >>= 1;
	}
	return res;
}

int get_rt(int x){
	int t = x - 1;
	// get();
	// printf("%d\n", tot);
	for (int i = 2; i * i <= t; i++){
		if(t % i == 0){
			fa[cnt++] = i;
			while(t % i == 0) t /= i;
		}
	}
	if(t > 1) fa[cnt++] = t;
	int f = 0;
	for (int i = 2; i < x; i++){
		f = 0;
		for (int j = 0; j < cnt; j++){
			if(poww(i, (x - 1) / fa[j], x) == 1) {f = 1; break;}
		}
		if(!f) return i;
	}
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	scanf("%d %lld", &p, &n);
	int rt = get_rt(p);
	LL leave = n % (p - 1), num = n / (p - 1);
	LL mul = 1, ans = 0;
	for (int i = 1; i < p; i++) mul = mul * rt % p, a[mul] = i;
	for (int i = 2; i < p; i++) b[__gcd(a[i], a[i - 1])] = 1;
	for (int i = 1; i < p; i++) printf("%d ", a[i]);
	printf("\n");
	for (int i = 1; i < p; i++){
		for (int j = i << 1; j < p && !b[i]; j += i) b[i] |= b[j];
	}
	for (int i = 1; i < p; i++) if(b[__gcd(i, p - 1)]) ans += num + (i <= leave);
	printf("%lld\n", ans);

	return 0;
}
/**/

 

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