POJ 1811

应该是两个算法的入门题、、、认真看了一上午算法导论,做掉了、、

RE好多次、、原来是编译器问题 换了C++ 就AC了、、、

乘法要用二进制相乘 否则会爆long long

#include <cstdio>
#include <cstdlib>
#include <ctime>
typedef long long LL;
int T;
LL n, s;
LL factor[110000];
LL mods(LL x, LL y, LL n){
	x %= n;
	y %= n;
	LL tmp = 0;
	while(y){
		if(y & 1)
			tmp = (tmp + x) % n;
		x = (x << 1) % n;
		y >>= 1;
	}
	return tmp;
}
LL pow(LL x, LL y, LL n)
{
	x %= n;
	LL tmp = 1;
	while(y){
		if(y&1) tmp = mods(tmp, x, n);
		x = mods(x, x, n);
		y >>= 1;
	}
	return tmp;
}
int judge(LL tmp, LL n, LL m, LL t){//n - 1 == m * 2^ t
	LL tp = m;
	LL v = pow(tmp , m, n);
	LL last = v;
	for(LL i = 1; i <= t; i++){
		v = mods(v, v, n);
		if(v == 1){
			if(last != 1 && last != n-1)
				return 0;
		}
		last = v;
		tp <<= 1;
	}
	if(v == 1)return 1;
	return 0;
}
int miller_rubin(LL x, int k){
	LL cnt = 0;
	LL m = x - 1;
	while(!(m & 1)) cnt++, m >>= 1;
	while(k--){
		LL tmp = rand()%(x-1) + 1;
		if(!judge(tmp, x, m, cnt)){
			return 0;
		}
	}
	return 1;
}
LL gcd(LL a, LL b){
	return b == 0?a: gcd(b, a%b);
}
LL f(LL x, LL n, LL c){
	return (mods(x, x, n) + c) % n;
}
LL poll(LL n, LL c){
	if(!(n & 1))return 2;
	LL x = rand() % n;
	LL y = x;
	LL i = 1;
	LL k = 2;
	while(1){
		i++;
		x = f(x, n, c);
		LL d = gcd(y - x + n, n);
		if(d != 1 && d != n)
			return d;
		if(y == x)return n;
		if(i == k){
			y = x;
			k += k;
		}
	}
}
void find(LL n){
	if(miller_rubin(n,5)){
		factor[s++] = n;
		return;
	}
	LL p = n;
	while(p >= n) p = poll(p, (LL)(rand()%(n-1)+1));
	find(p);
	find(n/p);
}
int main(){
	srand(time(NULL));
	scanf("%d",&T);
	while(T--){
		scanf("%lld",&n);
		if(n == 1)break;
		s = 0;
		find(n);
		if(s == 1){
			printf("Prime\n");
			continue;
		}
		LL tp = 10000000000LL;
		for(int i = 0; i < s; i++){
			if(tp > factor[i])
				tp = factor[i];
		}
		printf("%lld\n",tp);	
	}
	return 0;
}




你可能感兴趣的:(POJ 1811)