#约数#洛谷 4296 [AHOI2007]密码箱

题目

给定(n(nleq 2*10^9)),求

[sum_{x=1}^n[x^2mod n==1] ]


分析

首先当(n=1)的时候需要特判,
否则1和(n-1)一定是答案,
那么对于一个(x=x'+1)来说,也满足
((x'+1)^2mod n==1)
把这个式子拆开可以得到
(x'(x'+2)mod n==0)
那么考虑枚举(n)(geqsqrt{n})的约数,
那么(x')或者(x'+2)一定是这个数的倍数,
再枚举这个约数的倍数判断是否满足上式即可,
再通过(x')就可以推出(x)
PS:为什么不直接枚举(n)的约数?
因为(<sqrt{n})的约数所对应的另一个数也就是(>sqrt{n})的约数
当枚举(geqsqrt{n})的约数的倍数,
如果满足上式也就说明
(x',x'+2)的另一个数就是(leqsqrt{n})的约数的倍数
而枚举(leqsqrt{n})的倍数显然会T飞,
那还不如只枚举(geqsqrt{n})的约数的倍数,
时间复杂度不会证,也许是(O(sqrt{n}log{n}))


代码

#include <cstdio>
#include <algorithm>
#define rr register
using namespace std;
int n,m,a[100011];
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
signed main(){
	scanf("%d",&n),a[1]=1,a[m=2]=n-1;
	if (n==1) return !printf("None");
	for (rr int i=2;i*i<=n;++i)
	if (n%i==0){
		for (rr int j=n/i;j<n;j+=n/i){
		    if (1ll*j*(j+2)%n==0) a[++m]=j+1;
		    if (1ll*j*(j-2)%n==0) a[++m]=j-1;
		}
	}
	sort(a+1,a+1+m),m=unique(a+1,a+1+m)-a-1;
	for (rr int i=1;i<=m;++i) print(a[i]),putchar(10);
	return 0;
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13819732.html