【題解】UVA - 11255(Burside)

【題解】UVA - 11255(Burside)

OI生涯第一道Burside?

上次倫的火箭課件已經進行了掃盲,具體來說,定理內容是這樣的:

從我淺薄的知識來看,Polya只是Burside的計數版本

Burside

設置換羣\(G\),以及一個可以被這個羣作用的集合\(S\),那麼\(G_S\)的軌道數量(本質不同的\(S\)中的元素)是:
\[ \sum_{g\in G} {|\text{stab }S_g|\over |G|} \]
證明被我吃了

  • 旋轉同構

    • 考慮順時針轉\(k\in[1,n]\)步,對於旋轉\(k\)步,總共有\(\gcd (k,n)\)種不同的"循環"需要填,這些循環必須滿足循環內所有元素相同(這樣才能保持旋轉時不會造成不同)。每個循環的長度是\(n\over \gcd(k,n)\),直接算即可。
  • 翻轉同構(len=2)

    • 加旋轉的翻轉,意義是有\(n\)種對稱軸,同樣地計算一下就行了。

      • 奇數

        枚舉翻轉的那個顏色,再進行翻轉。

      • 偶數

        • 對稱軸經過兩個點

          • 枚舉兩個點的顏色即可
        • 對稱軸經過一個空隙
        • 直接算就好了

關鍵是恰當地對置換進行分類

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
const int maxn=40+5;
ll c[maxn][maxn];
void pre(const int&n){
    for(int t=0;t<=n;++t)
        for(int i=c[t][0]=1;i<=t;++i)
            c[t][i]=c[t-1][i-1]+c[t-1][i];
}
int a[3],b[3],n;

ll Polya(int k){
    int s=0;
    for(int t=0;t<3;++t)
        if(b[t]%k||b[t]<0) return 0;
        else b[t]/=k,s+=b[t];
    ll ret=1;
    for(int t=0;t<3;++t)
        ret*=c[s][b[t]],s-=b[t];
    return ret;
}

int main(){
    pre(41);
    int T;
    cin>>T;
    size_t siz=sizeof a;
    while(T--){
        n=0;
        for(int t=0;t<3;++t) cin>>a[t],n+=a[t];
        ll ans=0;
        for(int t=1;t<=n;++t)
            memcpy(b,a,siz),ans+=Polya(n/__gcd(t,n));
        if(n&1)
            for(int t=0;t<3;++t)
                memcpy(b,a,siz),--b[t],ans+=Polya(2)*n;
        else{
            for(int t=0;t<3;++t)
                for(int i=0;i<3;++i)
                    memcpy(b,a,siz),--b[t],--b[i],ans+=Polya(2)*n/2;
            memcpy(b,a,siz),ans+=Polya(2)*n/2;
        }
        cout<<ans/(n<<1)<<endl;
    }
    return 0;
}


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