Comet OJ - Contest #10 C 鱼跃龙门(质因数分解&扩展欧几里得)

Comet OJ - Contest #10 C 鱼跃龙门(质因数分解&扩展欧几里得)

题目大意

给定一个正整数 n,一共有 n 座龙门,跳过第 j (j

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

解题思路

设跳动次数为i,则当 n ∣ i ( i + 1 ) 2 n|{i(i+1)\over 2} n2i(i+1)时满足条件,由此得出方程
{ p x − q y = 1 x ∗ y = 2 n \begin{cases} px-qy&=1\\ x*y&=2n \end{cases} {pxqyxy=1=2n
最小的i即最小的qy,由此得出答案

但实际上这题卡了 n \sqrt n n 的分解因数,因此需要先素数筛筛出所有的素数,然后实现 O ( n log ⁡ n ) O(\frac{n}{\log n}) O(lognn)分解

AC代码

#include
using namespace std;
typedef long long LL;
const int size=1e6+5;
bool prime[size];
int p[size],tol;
void init()
{
	for(int i=0;i<size;i++) prime[i]=true;
	for(int i=2;i<size;i++)
	{
		if(prime[i]) p[++tol]=i;
		for(int j=1;j<=tol&&i*p[j]<size;j++)
		{
			prime[i*p[j]]=false;
			if(i%p[j]==0) break;
		}
	}
}
inline LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b == 0){
        x = 1,y = 0;
        return a;
    }
    LL g = exgcd(b,a%b,x,y);
    LL tep = x;
    x = y;
    y = tep-a/b*y;
    return g;
}
LL num[32],cnt[32];
int tot;
LL quick_pow(LL a,LL b){LL ans=1;while(b){if(b&1) ans=ans*a;a=a*a;b>>=1;} return ans;}
int main()
{
 	int t;
 	scanf("%d",&t);
 	init();
 	while(t--)
 	{
 		LL n;
 		scanf("%lld",&n);
 		n=n*2;
 		LL tmpn=n;
 		tot=0;
 		for(int i=1;i<=tol&&p[i]*p[i]<=n;i++)
 		{
 			if(n%p[i]==0)
 			{
 				num[++tot]=p[i];
 				cnt[tot]=0;
 				do{
 					cnt[tot]++;
 					n/=p[i];
 				}while(n%p[i]==0);
 			}
 		}
 		if(n!=1) {num[++tot]=n;cnt[tot]=1;}
 		for(int i=1;i<=tot;i++) num[i]=quick_pow(num[i],cnt[i]);
 		n=tmpn;
 		LL ans=2*n-1;
 		for(int i=0;i<(1<<tot);++i)
 		{
 			LL x=1;
 			for(int j=0;j<tot;++j)
 			{
 				if((1<<j)&i)
 					x=x*num[j+1];
			}
			LL y=n/x;
			LL p,q;
			LL r=exgcd(x,-y,p,q);
			q/=r;
			q%=x;
			if(q<=0) q+=x;
			ans=min(ans,q*y);
		}
		printf("%lld\n",ans);
	}
} 			

你可能感兴趣的:(数论)