【擴展歐幾里得】總結//poi 2002 Counting-Out Rhyme


        

              作爲一個oier,居然現在才弄擴展歐幾里得,以前屢屢沒有遇到,去年這個時候看了一點資料,但是沒有寫什麼題目,後來就忘記了,這次終於弄了一下。

              想想std用的居然還是一個頹頹的折半枚舉>.<, 羞愧ing

              

              題目化簡後變成,解一個方程組中A的最小解

                           A = k1 * d1 + b1;

                           A = k2 * d2 + b2;

                          ...

                          A  = k20 * d20 + b20; 

                      d1~20, b1~20 已知。

              首先整理一下擴展歐幾里得算法(儘量詳細一點):

               

               【1】 歐幾里得算法: 由於gcd(a,b) = gcd(b, a%b) //a>= b, 每次遞歸或迭代處理。

               

               【2】 求一組解 (x,y)滿足:gcd(a,b)= a * x + b * y 的一組;

                                 由於 a*x1 + b*y1 = gcd(a,b)

                                          b*x2 + a%b*y2 = gcd(b,a%b)

                                 所以 a*x1+b*y1 = b*x2 + a%b*y2  (考慮使用算數基本定理)

                                         a*x1 + b*y1 = b*x2 + a*y2 - a/b * b*y2  (“/”是指整除)

                                         合併得: a*x1 + b*y1 =a*y2  +  b* (x2 - a/b*b*y2)

                                 使用算數基本定理: x1 = y2 , y1 = x2 - a/b*b*y2;

                                 所以在回溯的時候,利用x2,y2 得到 x1, y1;

               

                【3】求x儘量小且爲正整數的一組(x,y)呢?

                                   化簡 a/gcd(a,b) * x  + b/gcd(a,b) * y  = 1. 現在已知一組解(x1,y1)

                                   x  每增加b/gcd(a,b), y減少a/gcd(a,b), 反之亦然。

                                   另mo = b/gcd(a,b)那麼min(x) =   (x1 % mo + mo) % mo; 然後對應的y可以求出。

               

                【4】 如果求a*x + b*y =  c 的一組x最小正解呢?

                                   如果c % gcd(a,b) != 0  則無解。

                                   那麼a/gcd(a,b) * x + b/ gcd(a,b) * y  = c / gcd(a,b); 兩邊再同時處以c/gcd(a,b),

                                   化爲a*x + b*y = 1 的形式,得到一組(x1,y1), 然後x1*= c/gcd(a,b), y1 *= c/gcd(a,b),

                                   由於a/gcd(a,b) + b/ gcd(a,b) 互質,仍然可以用上面的方法求出x爲最小正整數的解(x,y)

               

                【5】 迴歸原題,如果可以把20個式子化爲1個,可以輕易地求出最小的A

                            將A = ki * di + bi,  A = kj*dj + bj合併:

                            首先:  di * ki - dj * kj = bj - bi

                                   進一步用上面的方法化成 a*x - b*y = 1  的形式,只是如果把負數遞歸進gcd,必定會出問題,我們可以先求出 a * x + b * y = 1的一組解,  

                            然後把y取反,在求x 的正最小解即可。

                                   用上面的方法可以解出A(ki*di + bi)的一個正最小值, 可以知道,新獲得的式子必定是A  = lcm(ki , kj) *d+ b 的形式,A已知了,b自然可以得到,

                           這樣兩個式子就被合併成一個式子了。

                  

                 poi2002  counting-out rhyme

                 給定約瑟夫環的出圈次序,求最小的k使得報k 的人出圈,出圈順序與輸入相符。

                 可以得到關於k  對於1,2,3,....,n的餘數,輕鬆用上面的方法合併等式,求出最小的k:

                

# include <cstdlib>
# include <cstdio>
# include <cmath>

using namespace std;

typedef long long int64;

int k, n,go[30], step[30], m[30];
int64 eb, k1, b1, d1, k2, b2, d2, k3, b3, d3, GCD;
int find(int s, int t)
{
	int now = s, ask = 0;
	for (;now !=t; )
	{
		if (++now > n) now = 1;
		if (!step[now]) ask++;
	}
	return ask;
}

void prepare()
{
	int now, i, c;
	for (now = go[1], m[n]= go[1], step[now]=true,i = n-1; i >= 1; i--)
		c = go[n-i+1], m[i] = find(now, c),now = c, step[now]=true;
	for (i = 1; i <= n; i++) m[i] %= i;
}

int64 gcd(int64 a, int64 b) {return !b?a:gcd(b,a%b);};
void ext_gcd(int64 a, int64 b, int64 &x, int64 &y)
{
	if (!b) x = 1, y = 0;
	else
	{
		ext_gcd(b, a%b, x, y);
		int64 tmp = x;
		x = y;
		y = tmp - a/b * y;
	}
}
bool update(int64 d2, int64 b2)
{
	eb = b2-b1; GCD = gcd(d1, d2);
	d1/= GCD; d2 /= GCD; 
	if (eb % GCD) return false; else eb /= GCD;
	ext_gcd(d1, d2, k1, k2);
	k2 = -k2;
	k1 *= eb; k2 *= eb;
	k1 = (k1 % d2 + d2)% d2;
	k2 = (k1 * d1 - 1) / d2;
    d3 = d1 * d2 * GCD;
    b3 = (k1 * d1 * GCD + b1) % d3;
    d1 = d3; b1 = b3;
}
int main()    
{
        int i;
	scanf("%d",&n);
	for (i = 1; i <= n; i++) 
	{
		scanf("%d", &k);
		go[k] = i;
	}
	prepare();
        d1 = 1;b1 = 0;
	for (i = 2; i <= n; i++)
	    if (!update(i,m[i])) break; 
	if (i > n) printf("%I64d", b1);
	else printf("no");
	return 0;
}

               

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章