Idempotents 数论

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


你可能感兴趣的:(Idempotents 数论)