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

题目

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

\[\sum_{x=1}^n[x^2\bmod n==1] \]


分析

首先当\(n=1\)的时候需要特判,
否则1和\(n-1\)一定是答案,
那么对于一个\(x=x'+1\)来说,也满足
\((x'+1)^2\bmod n==1\)
把这个式子拆开可以得到
\(x'(x'+2)\bmod n==0\)
那么考虑枚举\(n\)\(\geq\sqrt{n}\)的约数,
那么\(x'\)或者\(x'+2\)一定是这个数的倍数,
再枚举这个约数的倍数判断是否满足上式即可,
再通过\(x'\)就可以推出\(x\)
PS:为什么不直接枚举\(n\)的约数?
因为\(<\sqrt{n}\)的约数所对应的另一个数也就是\(>\sqrt{n}\)的约数
当枚举\(\geq\sqrt{n}\)的约数的倍数,
如果满足上式也就说明
\(x',x'+2\)的另一个数就是\(\leq\sqrt{n}\)的约数的倍数
而枚举\(\leq\sqrt{n}\)的倍数显然会T飞,
那还不如只枚举\(\geq\sqrt{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;
}
posted @ 2020-10-15 11:53  lemondinosaur  阅读(86)  评论(0)    收藏  举报