一、题目
二、解法
母函数和 polya \text{polya} polya的结合,外面套一个 burnside \text{burnside} burnside的框框,考虑如何算不动点个数。
有一个一般形式,对于一个置换
f
i
f_i
fi,设
m
j
m_j
mj为循环节长度为
j
j
j的个数,
c
c
c是颜色,答案的具体方案如下:
(
c
1
.
.
+
c
k
)
m
1
(
c
1
2
.
.
+
c
k
2
)
m
2
.
.
.
.
(
c
1
n
.
.
+
c
k
n
)
m
n
(c_1..+c_k)^{m_1}(c_1^2..+c_k^2)^{m_2}....(c_1^n..+c_k^n)^{m_n}
(c1..+ck)m1(c12..+ck2)m2....(c1n..+ckn)mn本题就可以用
d
p
dp
dp算上面的柿子啦,设
d
p
[
i
]
[
x
]
[
y
]
dp[i][x][y]
dp[i][x][y]为前
i
i
i个循环节,选了
x
x
x个
a
a
a颜色,
y
y
y个
b
b
b颜色,
c
c
c颜色个数可以用总和算,就不用加入状态里面了,转移就暴力,原谅我偷个懒,不详细讲了,剩下的康康代码吧。
#include <cstdio>
#include <vector>
using namespace std;
#define int long long
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,ans,a,b,c,f[125][45][45];
vector<int> v;
int phi(int x)
{
int r=x;
for(int i=2;i*i<=x;i++)
if(x%i==0)
{
r=r/i*(i-1);
while(x%i==0) x/=i;
}
if(x>1) r=r/x*(x-1);
return r;
}
int work()
{
f[0][0][0]=1;
for(int i=1,s=0;i<=v.size();i++)
{
int t=v[i-1];s+=t;
for(int x=0;x<=a;x++)
for(int y=0;y<=b;y++)
{
f[i][x][y]=0;
if(x>=t) f[i][x][y]+=f[i-1][x-t][y];
if(y>=t) f[i][x][y]+=f[i-1][x][y-t];
if(s-x-y<=c) f[i][x][y]+=f[i-1][x][y];
}
}
return f[v.size()][a][b];
}
signed main()
{
T=read();
while(T--)
{
a=read();b=read();c=read();
n=a+b+c;ans=0;
for(int i=1;i<=n;i++)
if(n%i==0)
{
v.clear();
for(int j=1;j<=i;j++)
v.push_back(n/i);
ans+=phi(n/i)*work();
}
if(n&1)
{
v.clear();
v.push_back(1);
for(int i=1;i<=n/2;i++)
v.push_back(2);
ans+=n*work();
}
else
{
v.clear();
for(int i=1;i<=n/2;i++)
v.push_back(2);
ans+=(n/2)*work();
v.pop_back();
v.push_back(1);
v.push_back(1);
ans+=(n/2)*work();
}
printf("%lld\n",ans/(2*n));
}
}