[AHOI2007]密码箱
[AHOI2007]密码箱
当\(n=1\)时无解,\(x=0\)时不成立。
暴力:\(O(n)\)
从\(1\)~\(n\)扫一遍。
扩展欧几里得
发现一下式子:\(x^2≡1(\mod n)\)
移项得:\(x^2+k*n=1\)
于是运用扩展欧几里得求得一组解,进行判断即可。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
vector <LL> ans;
LL n;
void exgcd(LL a, LL b, LL &x, LL &y)
{
if(!b)
{
x = 1, y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= (a / b) * x;
return;
}
int main()
{
scanf("%lld", &n);
if(n == 1)
{
puts("None");
return 0;
}
LL res, y;
exgcd(1, n, res, y);
LL tmp = res;
ans.clear();
while(tmp < n * n)
{
if((LL)sqrt(tmp) * sqrt(tmp) == tmp) ans.push_back(sqrt(tmp));
tmp += n;
}
tmp = res;
while(tmp > 0)
{
tmp -= n;
if((LL)sqrt(tmp) * sqrt(tmp) == tmp) ans.push_back(sqrt(tmp));
}
sort(all(ans));
for(int i = 0; i < ans.size(); ++ i) printf("%d\n", ans[i]);
return 0;
}
扫描*枚举
由上述思路:\(x^2+k*n=1\)可以换一个角度思考。
=>\((x+1)(x-1)=k*n\)
这个式子提示我们,\(n\)是\(x+1\)和\(x-1\)的因数,不妨设\(n=a*b\),需要满足:\(x-1|a\)、\(x+1|b\)或\(x-1|b\)、\(x+1|a\)。
那么枚举\(n\)的因数,选最大的往上枚举\(x\),最后判断。
另外,不开long long可能有意想不到的错误。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
LL n, cnt = 0, ans[100000];
int main()
{
scanf("%lld", &n);
if(n == 1)
{
puts("None");
return 0;
}
ans[cnt ++] = 1;
LL MAXN = sqrt(n), b;
//Time Complexity: O(n^{0.5}ln(n))
for(LL a = 1; a <= MAXN; ++ a)
{
if(n % a == 0)
{
b = n / a;//枚举 n 的两个因数
for(LL x = b + 1; x <= n; x += b) //枚举x-1|a&x+1|b的情况
{
if((x + 1) % a == 0) ans[cnt ++] = x;
}
if(a == b) break;
for(LL x = b - 1; x <= n; x += b) //枚举x-1|b&x+1|a的情况
{
if((x - 1) % a == 0) ans[cnt ++] = x;
}
}
}
sort(ans, ans + cnt);
cnt = unique(ans, ans + cnt) - ans;
for(int i = 0; i < cnt; ++ i) printf("%lld\n", ans[i]);
return 0;
}