[AHOI2007]密码箱

题目:
https://ac.nowcoder.com/acm/problem/19877
给定一个 n n n,求出所有 x x x,满足 x 2 ≡ 1 ( m o d n ) n ≤ 2 ∗ 1 0 9 x^2\equiv 1(mod\quad n)\quad n\le2*10^9 x21(modn)n2109

思路:
x 2 ≡ 1 ( m o d n ) ( x + 1 ) ( x − 1 ) ≡ 0 ( m o d n ) \begin{aligned} x^2&\equiv 1(mod\quad n)\\ (x+1)(x-1)&\equiv 0(mod\quad n)\\ \end{aligned} x2(x+1)(x1)1(modn)0(modn)
则存在 y y y,使得 ( x − 1 ) ( x + 1 ) = n y (x-1)(x+1)=ny (x1)(x+1)=ny
y = y 1 × y 2 , n = n 1 × n 2 y=y_1\times y_2,n=n_1\times n_2 y=y1×y2,n=n1×n2,因此 y 1 × n 1 × y 2 × n 2 = ( x − 1 ) ( x + 1 ) y_1\times n_1\times y_2\times n_2=(x-1)(x+1) y1×n1×y2×n2=(x1)(x+1),所以我们可以得到 y 1 × n 1 = ( x − 1 ) , y 2 × n 2 = ( x + 1 ) y_1\times n_1=(x-1),y_2\times n_2=(x+1) y1×n1=(x1),y2×n2=(x+1)(因为 x − 1 x-1 x1一部分来自 n n n,一部分来自 y y y,同理 x + 1 x+1 x+1)
所以我们可以直接在 n \sqrt{n} n 的时间内枚举 n 1 , n 2 n_1,n_2 n1,n2,然后暴力枚举 y 2 y_2 y2,判断 y 1 y_1 y1是否存在

/*program from Wolfycz*/
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
	int x=0,f=1; char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
	return x*f;
}
inline int read(){
	int x=0,f=1; char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)	putchar('-'),x=-x;
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
int n;
set<int>st;
void work(int a,int b){
	for (int i=1;1ll*i*b<=n;i++){//上界无所谓,反正答案取模
		if ((i*b+2)%a==0)	st.insert((i*b+1)%n);
		if ((i*b-2)%a==0)	st.insert((i*b-1)%n);
	}
}
int main(){
	n=read();
	for (int i=1;i*i<=n;i++){
		if (n%i)	continue;
		work(i,n/i);
	}
	for (set<int>::iterator it=st.begin();it!=st.end();it++)	printf("%d\n",*it);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值