链接
题目描述
给定n,求出所有正整数x,满足小于n,且x^2(%n)=1
将满足的x按从小到大的顺序依次换行输出
思路
x 2 ≡ 1 ( m o d n ) x^2 \equiv 1(\bmod\ n) x2≡1(mod n)
( x + 1 ) ( x − 1 ) = k n (x+1)(x-1) = kn (x+1)(x−1)=kn
( x + 1 ) = k 1 n 1 ( k 1 ∣ k , n 1 ∣ n ) (x+1) = k_1n_1 (k_1|k, n_1|n) (x+1)=k1n1(k1∣k,n1∣n)
( x − 1 ) = k 2 n 2 ( k 2 ∣ k , n 2 ∣ n ) (x-1) = k_2n_2(k_2|k, n_2|n) (x−1)=k2n2(k2∣k,n2∣n)
那么很显然因为 k 1 n 1 ⩽ n k_1n_1 \leqslant n k1n1⩽n,所以 k 1 ⩽ n n 1 k_1 \leqslant \frac{n}{n_1} k1⩽n1n
那肯定不能让 n 1 n_1 n1太小,要不然就T飞了
又可以发现 n 1 n 2 = n n_1n_2 = n n1n2=n
那么 n 2 = n n 1 n_2 = \frac{n}{n_1} n2=n1n
那是不是只需要枚举一个大于 n \sqrt{n} n的 n n n的约数,然后再求 n 2 n_2 n2,验证求出的x是否为 n 2 n_2 n2的倍数就好了
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
ll n, cnt, t;
ll ans[500005], an[500005];
bool check(ll a)
{
for(int j = 0; j * a <= n; ++j)
{
ll a2 = n / a;
if((j * a - 2) % a2 == 0)
ans[++cnt] = j * a - 1;
if((j * a + 2) % a2 == 0)
ans[++cnt] = j * a + 1;
}
}
int main()
{
scanf("%lld", &n);
if(n == 1) {
printf("None\n");
return 0;
}
for(ll i = 1; i <= floor(sqrt(n)); ++i)
{
if(n % i == 0 && i * i != n)
an[++t] = n / i;
else if(i * i == n)
{
an[++t] = i;
break;
}
}
for(int i = 1; i <= t; ++i) check(an[i]);
sort(ans + 1, ans + cnt + 1);
int m = unique(ans + 1, ans + cnt + 1) - ans - 1;
int l = 1, r = m;
while(ans[l] < 0) l++;
while(ans[r] >= n) r--;
if(r - l + 1 == 0) {
printf("None\n");
return 0;
}
for(int i = l; i <= r; ++i)
printf("%lld\n", ans[i]);
return 0;
}