#约数#洛谷 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;
}

浙公网安备 33010602011771号