挑战性题目DSCT501:大整数因子分解

挑战性题目DSCT501:大整数因子分解

问题描述

大整数质因子分解。

题解

笑死,数据结构课背包都不讲,却给学生出泼辣肉,我的心里只有感恩。

因为本题的数据范围巨大,传统的O(n)O(\sqrt n)O(n)的质因数分解已经不适用,需要另外的算法。

首先是质数探测算法——Miller_rabin算法,其基于费马小定理,若p是质数,ap−1≡1(mod  p)a^{p-1}\equiv1\left(\mod p\right)ap11(modp)。同时,若ppp为质数,x2≡1(mod  p)x^2\equiv1\left(\mod p\right)x21(modp)可推出x=1 or p−1x=1\ or\ p-1x=1 or p1。所以,我们要判断一个质数是否是质数时,先套费马小定理判断,如果符合费马小定理,再判断(n−1)/2(n-1)/2(n1)/2是否满足上述第二个性质,如果对于一个预先设定的质数集合p[](本人使用的集合为2,325,9375,28178,450775,9780504,17952650222, 325, 9375, 28178, 450775, 9780504, 17952650222,325,9375,28178,450775,9780504,1795265022),数字nnn均通过上述检验,则认为其是质数。

之后,再利用大整数因数探测算法Pollar_Rho算法,若正整数nnn至少有一个因子不超过n\sqrt nn,设它任意一个因子为ppp,若随机生成ppp以内的数,期望O(p)O\left(\sqrt p\right)O(p)次就可以随机到两个一样的数。

随机生成[1,n][1,n][1,n]的正整数,它们mod pmod\ pmod p下可近似看做在[1,p][1,p][1,p]内随机,随机生成两个数a,b(b>a)a,b(b>a)a,b(b>a),若b=a(mod p)→p∣(b−a)→gcd(n, b−a)≥pb=a(mod\ p)\rightarrow p|(b-a)\rightarrow gcd(n,\ b-a)\geq pb=a(mod p)p(ba)gcd(n, ba)p

那么gcd(n,b−a)gcd\left(n,b-a\right)gcd(n,ba)必为nnn的一个大于111的因数。令随机数这样生成:a0=C,f(x)=x2+C,ai=f(ai−1)a_0=C,f\left(x\right)=x^2+C,a_i=f\left(a_{i-1}\right)a0=C,f(x)=x2+C,ai=f(ai1)即跳一步就套用一次f(x)f\left(x\right)f(x)。这样做的好处是:若ax=ay(mod  p)→ax+1−ay+1=f(ax)−f(ay)=(ax+ay)(ax−ay)=0(mod  p)a_x=a_y\left(\mod p\right)\rightarrow a_{x+1}-a_{y+1}=f\left(a_x\right)-f\left(a_y\right)=\left(a_x+a_y\right)\left(a_x-a_y\right)=0(\mod p)ax=ay(modp)ax+1ay+1=f(ax)f(ay)=(ax+ay)(axay)=0(modp) 即任一距离为ddd的随机数mod  p\mod pmodp相同,所有距离为ddd的随机数mod  p\mod pmodp都相同,这样只需要检查其中一个即可。

免除记忆化:维护两个数,一个数每次调用两次fff,一个每次调用一次,如果走完了环,最后两个数一定会相遇。同时也枚举了所有距离。

优化:瓶颈在于gcdgcdgcd,可以减少取gcd(n,∣a−b∣)gcd\left(n,\left|a-b\right|\right)gcd(n,ab)的次数,将所有的∣a−b∣\left|a-b\right|ab乘起来,累计128128128次后再与nnngcdgcdgcd(前提是a,ba,ba,b还没有在环上相遇),复杂度约为O(n1/4)O(n^{1/4})O(n1/4)

代码

感谢我的超人——Rockdu提供的泼辣肉模板,说实话我也没怎么搞懂,以后有缘再学。

#pragma GCC optimize(2) 
#include<bits/stdc++.h>
#define LL long long
using namespace std;

LL n;

namespace NT {
	LL gcd(LL a, LL b) {
		return b ? gcd(b, a % b) : a;
	}
	LL mul(LL a, LL b, LL m) {
		LL s = a * b - (LL)((long double)a * b / m + 0.5) * m;
		return s < 0 ? s + m : s;
	}
	LL fpow(LL x, LL a, LL m) {
		LL ans = 1;
		while(a) {
			if(a & 1) ans = mul(ans, x, m);
			x = mul(x, x, m), a >>= 1;
		}
		return ans;
	}
}

namespace Miller_Rabin {
	using namespace NT;
	LL p[15] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
	int detect(LL n, LL a) {
		if(n == a) return 1;
		if(a % n == 0) return 1;
		LL now = n - 1, lst = 1;
		if(fpow(a, now, n) != 1) 
			return 0;
		while(!(now & 1)) {
			now /= 2;
			LL p = fpow(a, now, n);
			if(lst == 1 && p != 1 && p != n - 1)
				return 0;
			lst = p;
		}
		return 1;
	}
	
	LL MR(LL n) {
		if(n < 2) return 0;
		for(int i = 0; i < 7; ++i) {
			if(!detect(n, p[i])) 
				return 0;
		}
		return 1;
	}
}

namespace Pollard_Rho {
	using namespace NT;
	using namespace Miller_Rabin;
	LL f(LL x, LL C, LL p) {
		return (mul(x, x, p) + C) % p;
	}
	LL Rand() {return (rand() << 15) + rand();}
	LL Randll() {return (Rand() << 31) + Rand();}
	
	LL PR(LL n) {
		if(n == 4) return 2;
		if(MR(n)) return n;
		while(1) {
			LL C = Randll() % (n - 1) + 1;
			LL s = 0, t = 0;
			LL acc = 1;
			do {
				for(int i = 1; i <= 128; ++i) {
					t = f(f(t, C, n), C, n);
					s = f(s, C, n);
					LL tmp = mul(acc, abs(t - s), n);
					if(s == t || tmp == 0)
						break;
					acc = tmp;
				}
				LL d = gcd(n, acc);
				if(d > 1) return d;
			} while(s != t);
		}
	}
	
	typedef pair<LL, int > pii;
	vector<pii > DCOMP(LL n) {
		vector<pii > ret;
		while(n != 1) {
			LL p = PR(n);
			while(!MR(p)) 
				p = PR(p);
			int c = 0;
			while(n % p == 0) n /= p, ++c;
			ret.push_back(make_pair(p, c));
		}
		return ret;
	}
}
void out(long long x){if(x>9)out(x/10);putchar(x%10+'0');}
int main(int argc,char* argv[]) {
	srand(19260817);
	LL n=atoll(argv[1]);
	if(n==1)return 0; 
	auto ans = Pollard_Rho::DCOMP(n);
	out(ans[0].first);
	ans[0].second--;
	for(auto i : ans)
		while(i.second--) putchar('*'),out(i.first);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值