jzoj7177质因数分解扩展欧几里得鱼跃龙门

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj7177质因数分解扩展欧几里得鱼跃龙门相关的知识,希望对你有一定的参考价值。

题面

Description

给定一个正整数 n n n,一共有 n n n座龙门,跳过第 j ( j < n ) j (j<n) j(j<n)座龙门将会到达第 j + 1 j+1 j+1座龙门前,特殊地,跳过第 n n n座龙门后将会到达第 1 1 1 座龙门前。

胖头鱼一开始在第一座龙门前,接下来,第 i i i个时刻内它会向前跳 i i i次,每次跳过 1 1 1座龙门,求最小的正整数 x x x满足第 x x x个时刻结束后胖头鱼恰好会回到起点。

Input

第一行一个整数 T T T,表示数据组数。
接下来 T T T行,每行一个整数 n n n,表示一共有 n n n座龙门。

1 ≤ T ≤ 100 1 \\le T \\le 100 1T100, 1 ≤ n ≤ 1 0 12 1 \\le n \\le 10^{12} 1n1012

Output

一共 T T T行,每行一个整数 x x x,表示答案。

样例1

样例输入 1

5
2
4
6
8
10

样例输出 1

3
7
3
15
4

样例解释 1

n = 10 n=10 n=10的样例解释:
一开始在 1 1 1的前面也就是位置 0 0 0
第一时刻跳一步到 ( 0 + 1 )   m o d   n = 1 (0+1) ~ mod ~ n = 1 (0+1) mod n=1
第二时刻跳两步到 ( 1 + 2 )   m o d   n = 3 (1+2) ~mod ~ n = 3 (1+2) mod n=3
第三时刻跳三步到 ( 3 + 3 )   m o d   n = 6 (3+3) ~mod ~ n = 6 (3+3) mod n=6
第四时刻跳四步到 ( 6 + 4 )   m o d   n = 0 (6+4) ~ mod ~ n = 0 (6+4) mod n=0
第四时刻后恰好跳回原点 0 0 0,所以答案为 4 4 4

样例2

样例输入 2

10
200479710
1041705379
766770747
257088468
877586977
86834214
757618747
884911150
388001368
494728090

样例输出 2

30464759
9427197
74899308
9020648
877586976
43417107
96416647
212378675
43718463
36697240

解题思路

一开始想岔了(因为数论太烂),把想法写的贼牛的样子(式子貌似也写错了(((()
∑ i = 1 x i ≡ 0 ( m o d   n ) {\\sum_{i=1}^{x}i}\\equiv 0(mod\\ n) i=1xi0(mod n)
x即
后面才发现这个式子是可以简化的, n ∣ ( x ( x + 1 ) / 2 ) → 2 n ∣ x ( x + 1 ) n|(x(x+1) / 2)\\rightarrow 2n|x(x+1) n(x(x+1)/2)2nx(x+1)
a ∣ 2 n , b = 2 n / a a|2n,b=2n/a a2n,b=2n/a,则( a b = 2 n ab=2n ab=2n a b ∣ x ( x + 1 ) ab|x(x+1) abx(x+1)
a p ⋅ b q = x ( x + 1 ) ap·bq=x(x+1) apbq=x(x+1),设 a p = ( x + 1 ) , b q = x ap=(x+1),bq=x ap=(x+1),bq=x,则 a p − b q = 1 ap-bq=1 apbq=1

引用扩展欧几里得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
套上去就是 a x + b y = 1 ax+by=1 ax+by=1(-号可以算进系数y中),用扩欧求解
这就产生一个条件了, g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1(即a,b互质),于是就可以先处理出2n的质因子

#tips
在这里插入图片描述
在这里插入图片描述
感谢LTH大爷 (虽然还是看不懂)


Code

#include <iostream>
#include <cstring>
#include <cstdio>
#define ll long long

using namespace std;

const int maxn = 1e6 + 5;
const ll INF = 1e18;
ll n, ans, f[maxn + 100], p[maxn + 100];
int num, T;

void init() {
	f[0] = f[1] = 1;
	for(int i = 2; i <= maxn; i++) {
		if(!f[i]) p[++num] = i;
		for(int j = 1; j <= num && i * p[j] <= maxn; j++) {
			f[i * p[j]] = 1;
			if(i % p[j] == 0) break;
		}
	}
}

void demo(ll n) {
	f[0] = 0;
	for(int i = 1; i <= num && p[i] <= n; i++) {
		if(n % p[i] == 0)
			f[++f[0]] = 1;
		while(n % p[i] == 0){n /= p[i], f[f[0]] *= p[i];}
	}
	if(n > 1)
		f[++f[0]] = n;
}

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

void dfs(int now, ll a, ll b) {
	if(now == f[0] + 1) {
		ll x, y;
		work(a, b, x, y);
		y = -y % a;
		if(y <= 0) y += a;
		ans = min(ans, y * b);
		return;
	}
	dfs(now + 1, a * f[now], b);
	dfs(now + 1, a, b * f[now]);
}

int main() {
	init();  //把质数处理出来
	scanf("%d", &T);
	while(T--) {
		scanf("%lld", &n);
		n *= 2;
		demo(n);  //把2n的质因数求出来
		ans = INF;
		dfs(1, 1, 1);  //dfs出a,b的可能性,找到最小的解
		printf("%lld\\n", ans);
	}
}

以上是关于jzoj7177质因数分解扩展欧几里得鱼跃龙门的主要内容,如果未能解决你的问题,请参考以下文章

2021.7.15提高B组模拟4T3 鱼跃龙门(exgcd)

jzoj 6301. 普及组

code lib map

[JZOJ 5791] 阶乘

Python版本的常见模板 数论

JZOJ6368质树(tree)