正题
题目链接:
https://www.luogu.org/problemnew/show/P2090
大意
一个数对(a,b),每次可以变为(a+b,b)或(a,a+b)。然后要求一个数对中有n求从(1,1)变成这个数对的最小次数。
解题思路
更相减损法是gcd(a,b)=gcd(a,b-a)/gcd(a-b,b)
证明:
a∣d,b∣da∣d,b∣d
所以
(a−b)∣d(a−b)∣d
我们设 a′=ba′=b, b′=a−bb′=a−b
那么
gcd(a,b)=gcd(a,a+b)gcd(a,b)=gcd(a,a+b)
没错,是不是有些眼熟。更相减损术的次数就是到达一个数对需要的最少次数。
我们就可以枚举一个 xx,然后求数对的最小次数。
但是!
会超时。然后我们就可以用欧几里得算法
我们可以发现(b,a−b)(b,a−b)进行xx次就是。所以我们可以发现如果要从
(b,a−bx)(b,a−bx)变到(b,a%b)(b,a%b),xx需要等于,所以我们可以用一个wgcd(x,y)wgcd(x,y)表示变到数对(x,y)(x,y)需要的次数,当b=1b=1时我们只可以将11不断累加到上面所以需要的次数就是a−1a−1次
返回
wgcd(x,y)⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪x−1 (y=1)inf (y=0)⌊a/b⌋+wgcd(y,x%y) (y>1)wgcd(x,y){x−1(y=1)inf(y=0)⌊a/b⌋+wgcd(y,x%y)(y>1)
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n,mins;
int gcd(int x,int y)//wGCD
{if (y==1) return x-1;if (!y) return 1e9;return x/y+gcd(y,x%y);
}
int main()
{mins=2147483647;scanf("%d",&n);for (int i=1;i<=(n+1)/2;i++)//枚举(n,i)mins=min(mins,gcd(n,i));printf("%d",mins);
}