poj 2409 Let it Bead Polya定理

題意:用c種顏色給長度爲s的項鍊染色,一共有多少種方案


思路:網選後天就來了,這兩天補了下Polya定理,剛好又在學習密碼學,順便補了羣的一些東西。對於這種存在置換後存在一個等價類的計數問題,我們可以用Burnside引和Polya定理,Polya定理是由Burnside定理推導出來的,學習過程應該是羣->置換羣->Burnside引理->Polya定理,同時可以看見的是儘管Polya定理是由Burnside引理推導出來的,但也可以看作是兩個看問題不同的角度而得出的結論,Burnside引理着眼於染色,如果顏色種類過多和被染色的圖形過於複雜,那麼Burnside引理將很難操作,而Polya定理則着眼於圖形的結構,使問題的複雜性大大降低,數學真是處處充滿哲理,不同角度看問題可能會產生非常大的差別


按照順時針方向從0到n - 1進行編號,Polya定理是對結構進行置換,只考慮旋轉的話,有n種結構,分別是旋轉0, 1,  2, ... , n - 1,假定現在旋轉了k次,

那麼第i個鑽石和第(i + k * t)屬於同一個循環,那麼如果求出一個最小的t使得(i + k * t ) % n == i,那麼此時表明這個循環就有t個元素,上述式子可以推出i % n + k * t % n == i,可推出(k * t) % n == 0,此時t要取最小,必然t = n / gcd(k, n):t表示一個循環的階,那麼n / t就表示有多少個循環,從對稱性上講,也可看出是正確的。

當然還要考慮翻轉的情況


題目鏈接:http://poj.org/problem?id=2409


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

typedef long long ll;

ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

ll mypow(ll x, ll n)
{
	ll res = 1;
	while(n)
	{
		if(n & 1) res *= x;
		x *= x;
		n >>= 1;
	}
	return res;
}

ll c, s;

ll polya()
{
	ll ans = 0;
	for(ll i = 1; i <= s; i++)
		ans += mypow(c, gcd(i, s)); 
	if(s & 1)
		ans += s * mypow(c, (s + 1) / 2);
	else
		ans += (s / 2) * (mypow(c, s / 2 + 1) + mypow(c, s / 2));
	return ans / 2 / s;
}

int main()
{
	while(scanf("%lld%lld", &c, &s), c)
	{
		ll ans = polya();
		printf("%lld\n", ans);
	}
	return 0;
}


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