日常训练 20160601 B君的关系 羊毛 (Wolle) Burnside

来源:互联网 发布:淘宝代销怎么没有了 编辑:程序博客网 时间:2024/06/11 18:27

题意简述:给一个 n×m×p×q 的四位空间染 col 种颜色,四个方向上的平移置换和任意一种颜色排列的颜色置换所得方案算本质相同的方案,问本质不同的方案数。1n,m,p,q1000 ,1col16
如果不考虑颜色置换,枚举四个方向上置换走几步能走完 a,b,c,d (a | A,b | B,c | C,d | D),这样的置换有 φ(a)×φ(b)×φ(c)×φ(d) 种,一次从一个点走回原点的回路长度是 l=lcm(a,b,c,d) , 有 A×B×C×Dl 种这样的回路,每条回路里的每个元素都要相同,那么一条回路的着色方案只有 1 种,那么答案就是 φ(a)×φ(b)×φ(c)×φ(d)×cA×B×C×DlA×B×C×D
考虑一种排列的颜色置换,这种置换有用的不是置换本身,而是这个置换中的每个轮换的长度,考虑颜色置换中每一种轮换的长度,如果轮换长度len是回路长度l的因数,那么就会对回路贡献出len种色盲认不出的方案(颜色置换下的稳定核)。那么答案就是 φ(a)×φ(b)×φ(c)×φ(d)×(calc(l))A×B×C×DlA×B×C×D
本题是要考虑所有排列的颜色置换,那么先将 16 自然数拆分,有 231 种拆分,对一种拆分颜色置换其实本质相同,最后只要乘一个系数即可。一种拆分一个轮换内部元素可以随便换,相同大小的轮换之间也可以随便换,乘的系数就不难推出了。
最后除以置换方案种类数即可,别忘记除以颜色置换的方案种类数。

#include<bits/stdc++.h>#define pow HAtypedef long long ll;const int P = 1e9 + 7;int A, B, C, D, col, cnt, temp[20], sp[250][20], phi[1001], a[100], b[100], c[100], d[100];ll fac[20], kind[250], l, ans;void dfs(int dep, int n, int last) {    if (n == 0) {        cnt++;        for (int i=1; i < dep; i++)            sp[cnt][temp[i]]++;        return;    }    for (int i=n; i >= last; i--)        temp[dep] = i,        dfs(dep + 1, n - i, i);}ll gcd(ll a, ll b) {if (b == 0) return a; return gcd(b, a % b); }ll lcm(ll a, ll b) {return a * b / gcd(a, b); }ll pow(ll x, ll k) {    ll ans = 1;    for (; k; k >>= 1, x = x * x % P)        if (k & 1ll) ans = ans * x % P;    return ans;}ll calc(ll x, int i) {    ll ans = 0;    for (int j=1; j <= col; j++)        if (x % j == 0)            ans += sp[i][j] * j;    return ans;}void find(int n, int a[]) {    for (int i=1; i * i <= n; i++)        if (n % i == 0)            a[++a[0]] = i,            a[++a[0]] = n / i;    if (a[0] > 1 && a[a[0] - 1] == a[a[0]]) a[0]--;}void solve() {    fac[0] = 1;    for (int i=1; i <= col; i++)        fac[i] = fac[i - 1] * i % P;    for (int i=1; i <= 1000; i++) {        int t = phi[i] = i;        for (int j=2; j * j <= t; j++)            if (t % j == 0) {                phi[i] = phi[i] / j * (j - 1);                while (t % j == 0) t /= j;            }        if (t > 1) phi[i] = phi[i] / t * (t - 1);    }    find(A, a); find(B, b); find(C, c); find(D, d);    for (int i=1; i <= cnt; i++) {        ll tans = 0;        for (int ai=1; ai <= a[0]; ai++)            for (int bi=1; bi <= b[0]; bi++)                for (int ci=1; ci <= c[0]; ci++)                    for (int di=1; di <= d[0]; di++)                        l = lcm(lcm(a[ai], b[bi]), lcm(c[ci], d[di])),                        tans = (tans + (ll)phi[a[ai]] * phi[b[bi]] % P * phi[c[ci]] % P * phi[d[di]] % P                                 * pow(calc(l, i), (ll)A * B * C * D / l)) % P;        for (int j=1; j <= col; j++)            tans = tans * pow(pow(j, sp[i][j]) * fac[sp[i][j]] % P, P - 2) % P;        ans = (ans + tans * fac[col]) % P;    }    ans = ans * pow((ll)fac[col] * A % P * B % P * C % P * D % P, P - 2) % P;    printf("%lld\n",ans);}int main() {    scanf("%d%d%d%d%d",&A,&B,&C,&D,&col);    dfs(1, col, 1);    solve();    return 0;}