来源:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=9927#problem/H
题意:给你一个n,n是两个不同素数的乘积。让求小于等于n的x,满足x*x %n = x%n。
思路:其实就是求x * (x-1) 是n的倍数。我们可以把n分解成两个素数的乘积,即n = p * q,若x * (x - 1) 是n的倍数,则一定是通过p或者q的倍数得到的。我们假设是从p的倍数得到的,则x从p开始循环,若 x - 1 是q的倍数,则该x符合题意。同样的道理对于q也是一样的。这样的话,我们分别循环p和q的倍数即可。但是由于n比较大(10亿),所以普通方法肯定会超时。
其实这道题的正确方法是扩展欧几里得,但是我确实是完全忘了扩展欧几里得是怎么一回事,于是就想了个无耻的方法水过了。我的方法是:只循环max(p,q),循环的时候两个条件一起判断即可。由于max(p,q)最大在30000多,所以是可以水过的,跑了760ms,惭愧,,,
我的搓代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
using namespace std;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
const int N = 15;
int dp[N][N],num[10],prime[100010],flag[100010],KK = 0;
void init(){
CLR(flag,0);
for(int i = 2;i <= 100000;++i){
if(!flag[i]){
flag[i] = 1;
prime[KK++] = i;
for(int j = i*2;j <= 100000;j+=i)
flag[j] = 1;
}
}
}
int main(){
init();
int numcase;
scanf("%d",&numcase);
while(numcase--){
int n,p,q;
CLR(num,0);
scanf("%d",&n);
for(int i = 0;i < KK;++i){
if(n % prime[i] == 0){
p = prime[i];
q = n/prime[i];
break;
}
}
int cnt = 2,k = 1;
int minpri = min(p,q);
int maxpri = max(p,q);
int initnum = (maxpri+1)/minpri,initmax = maxpri,initmin = minpri,mmax = maxpri;
while(maxpri < n){
if((maxpri + 1) % initmin == 0){
num[cnt++] = maxpri + 1;
}
if((maxpri - 1)% initmin == 0){
num[cnt++] = maxpri ;
}
maxpri += mmax;
}
/* while(initmax < n){
if((initmax-1) % initmin == 0){
num[cnt++] = initmax;
}
initmax += mmax;
}*/
num[0] = 0;num[1] = 1;
sort(num,num+cnt);
for(int i = 0;i < cnt-1;++i){
printf("%d ",num[i]);
}
printf("%d\n",num[cnt-1]);
}
return 0;
}