「CQOI2016」密钥破解

题目链接


解题思路

我们只要求出(p)(q),问题就迎刃而解了。那么就需要Pollard_Rho算法(p)(q)。值得注意的是,由于(n)不是素数,所以求逆元的时候需要用(exgcd)而不是费马小定理。

参考程序

#include <bits/stdc++.h>
#define LL long long
using namespace std;

LL SlowMultiply( LL x, LL y, LL Mod ) {
	LL Ans = 0ll;
	for( ; y; y >>= 1, x = ( x + x ) % Mod ) 
		if( y & 1 ) 
			Ans = ( Ans + x ) % Mod;
	return Ans;
}

LL FastPow( LL x, LL y, LL Mod ) {
	LL Ans = 1ll;
	for( ; y; y >>= 1, x = SlowMultiply( x, x, Mod ) )
		if( y & 1 )
			Ans = SlowMultiply( Ans, x, Mod );
	return Ans;
}

LL gcd( LL x, LL y ) {
	LL m = x % y;
	while( m ) {
		x = y; y = m; m = x % y;
	}
	return y;
}

LL Pollard_Rho( LL N, LL Seed ) {
	LL x, y;
	x = y = rand() % N;
	y = ( SlowMultiply( y, y, N ) + Seed ) % N;
	while( x != y ) {
		LL d = gcd( ( x - y > 0 ) ? x - y : y - x, N );
		if( d > 1 ) return d;
		x = ( SlowMultiply( x, x, N ) + Seed ) % N;
		y = ( SlowMultiply( y, y, N ) + Seed ) % N;
		y = ( SlowMultiply( y, y, N ) + Seed ) % N;
	}
	return N;
}

void Exgcd( LL a, LL b, LL &x, LL &y ) {
	if( b == 0 ) {
		x = 1ll, y = 0ll;
		return;
	}
	Exgcd( b, a % b, y, x );
	y -= a / b * x;
	return;
}

LL Inv( LL a, LL b ) {
	LL x, y;
	Exgcd( a, b, x, y );
	if( x < 0 ) x += b;
	return x;
}

int main() {
	LL e, N, c;
	scanf( "%lld%lld%lld", &e, &N, &c );
	LL p = N, q = 1;
	for( LL Seed = 19260817; p == N; p = Pollard_Rho( N, Seed-- ) );	
	q = N / p;
	LL r = ( p - 1 ) * ( q - 1 );
	LL d = Inv( e, r );
	printf( "%lld %lld
", d, FastPow( c, d, N ) );
	return 0;
}

原文地址:https://www.cnblogs.com/chy-2003/p/10745197.html