[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
", 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
", ans[i]);
return 0;
}