UVA11255 Necklace

Link
先约定\(f(a,b,c)=\frac{(a+b+c)!}{a!b!c!}\)即可重集合的排列。
因为有了个数限制所有考虑Burnside,\(ans=|X/G|=\frac{\sum\limits_{g\in G}|X^g|}{\operatorname{ord}(G)}\)
对于旋转\(i\)位的置换,其循环节为\(l=\frac n{(n,i)}\),显然仅当\(l|a\wedge l|b\wedge l|c\)时可能存在不动点,不动点数\(f(\frac al,\frac bl,\frac cl)\)
然后考虑对称的置换,我们根据\(n\)的奇偶性分类讨论:
\(1.n\)为奇数:显然仅当\(a,b,c\)为一奇两偶时可能存在不动点,不动点数为\(nf(\lfloor\frac a2\rfloor,\lfloor\frac b2\rfloor,\lfloor\frac c2\rfloor)\)
\(2.n\)为偶数:显然仅当\(a,b,c\)中奇数的个数为偶数时可能存在不动点,不动点数还是\(nf(\lfloor\frac a2\rfloor,\lfloor\frac b2\rfloor,\lfloor\frac c2\rfloor)\)

#include<cstdio>
using i64=long long;
int gcd(int n,int m){return !m? n:gcd(m,n%m);}
i64 C[50][50];
i64 cal(int a,int b,int c){return C[a+b+c][a]*C[b+c][b];}
void solve()
{
    int a,b,c,n,f;i64 ans=0;
    scanf("%d%d%d",&a,&b,&c),n=a+b+c,f=(a&1)+(b&1)+(c&1);
    for(int i=0;i<n;++i)
    {
	int len=n/gcd(n,i);
	if(a%len||b%len||c%len) continue;
	ans+=cal(a/len,b/len,c/len);
    }
    if((n&1&&f==1)||!(n&1||f&1)) ans+=n*cal(a>>1,b>>1,c>>1);
    printf("%lld\n",ans/2/n);
}
int main()
{
    for(int i=0,j;i<=45;++i) for(j=C[i][0]=1;j<=i;++j) C[i][j]=C[i-1][j]+C[i-1][j-1];
    int T;scanf("%d", &T);
    while(T--) solve();
}
posted @ 2020-01-28 21:08  Shiina_Mashiro  阅读(124)  评论(0编辑  收藏  举报