GMOJ7177 鱼跃龙门题解

GMOJ 7177 鱼跃龙门 题解

题面
题面
显然是求最小的x 使得 x × ( x + 1 ) 2 ≡ 0 ( m o d    n ) \frac{x \times(x + 1)}{2} \equiv 0 (mod\; n) 2x×(x+1)0(modn)
x × ( x + 1 ) ≡ 0 ( m o d    2 n ) x \times (x + 1) \equiv0(mod\;2n) x×(x+1)0(mod2n)
d = g c d ( x , 2 n ) , x = x 1 d , 2 n = n 1 d . d=gcd(x,2n),\\x=x_1d,\\2n=n_1d. d=gcd(x,2n),x=x1d,2n=n1d.
x 1 d × ( x 1 d + 1 ) ≡ 0 ( m o d    n 1 d ) x_1d\times(x_1d+1)\equiv0(mod\;n_1d) x1d×(x1d+1)0(modn1d)
x 1 × ( x 1 d + 1 ) ≡ 0 ( m o d    n 1 ) x_1\times(x_1d+1)\equiv0(mod\;n_1) x1×(x1d+1)0(modn1)
注意到 g c d ( x 1 , n 1 ) = 1 gcd(x_1,n_1)=1 gcd(x1,n1)=1
x 1 d + 1 ≡ 0 ( m o d    n 1 ) x_1d+1\equiv0(mod\;n_1) x1d+10(modn1)
转换形式. 可得 − x 1 d + k n 1 = 1 -x_1d+kn_1=1 x1d+kn1=1
d d d为常量,可用扩展欧几里得算法求得一个小于 0 0 0 − x 1 -x_1 x1
因此最小的 x = x 1 d x=x_1d x=x1d
枚举 d d d即可.

#include <cstdio>
#include <iostream>
#include <cstring>
#define R register
using namespace std;
typedef long long LL;
const LL inf = 1e15;
LL x, yy, T, n, y[200000][2], cntP, cntY, vis[1000100], p[1000000];
LL ans = inf;
inline LL read() {
	LL res; char ch = getchar();
	for(; ch > '9' || ch < '0'; ch = getchar());
	for(res = 0; ch >= '0' && ch <= '9'; res = res * 10 + ch - '0', ch = getchar());
	return res;
}
inline LL gcd(LL a, LL b) {return b == 0 ? a : gcd(b, a % b);}
void exgcd(LL a, LL b) {
	if(b == 0) {
		x = 1, yy = 0;
		return ;
	}
	exgcd(b, a % b);
	LL tmp = x;
	x = yy;
	yy = tmp - a / b * yy;
	return ;
}
void check(LL now) {
	if(gcd(now, n / now) > 1) return ;
	exgcd(now, n / now);
	if(x >= 0) x = x % (n / now) - (n / now);
	x = -x * now;
	ans = min(ans, x);
}
void dfs(int k, LL now) {
	if(k > cntY) {
		check(now);
		return ;
	}
	LL tmp = now;
	for(R int i = 0; i <= y[k][1]; ++i) {
		dfs(k + 1, tmp);
		tmp /= y[k][0];
	}
	return ;
}
int main() {
	for(register int i = 2; i <= 1000000; ++i) {
		if(!vis[i]) p[++cntP] = i;
		for(register int j = 1; j <= cntP; ++j) {
			int tmp = p[j] * i;
			if(tmp > 1000000) break;
			vis[tmp] = 1;
			if(i % p[j] == 0) break;
		}
	}
	T = read();
	for(; T; T--) {
		n = read() * 2;
		LL tmp = n;
		ans = inf;
		memset(y, 0, sizeof(y));
		cntY = 0;
		for(R int i = 1; i <= cntP && p[i] <= tmp; ++i) {
			if(tmp % p[i] == 0) {
				++cntY;
				y[cntY][0] = p[i];
				while(tmp % p[i] == 0) {
					y[cntY][1] ++;
					tmp /= p[i];
				}
			}
		}
		if(tmp > 1) y[++cntY][0] = tmp, y[cntY][1] = 1;
		dfs(1, n);
		printf("%lld\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值