来源: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; }