UVA11255 Necklace

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

#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
",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();
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12238933.html