zoukankan      html  css  js  c++  java
  • [hdu 6360] Kaleidoscope

    题意

    给你(n)种颜色,让你给一个rhombic hexecontahedron的每一个面染色,要求第(i)种颜色使用不少于(a_i)次,求有多少本质不同的rhombic hexecontahedron。定义本质不同为存在一种旋转方案使得旋转前和旋转后不一样。

    答案对任意数(m)取模。

    rhombic hexecontahedron是什么呢?


    real!

    题解

    pólya练手题然而并不会。我真是个白学家。

    这个rhombic hexecontahedron本质上是从正十二面体进行一些操作变过来的。

    正十二面体长这样

    容易想到rhombic hexecontahedron的每个面都可以和正十二面体的每个顶点与做一个映射。这不是双射,因为正十二面体的每个顶点被三个面共用,所以要把一个点拆成三个,才能建立双射。

    但是实际上并不需要在十二面体上考虑,只是帮助我们思考旋转的问题。

    考虑有多少种不同的旋转作用在这个对象集合上:

    1.以两个相对面的中心连线为轴,可以旋转(frac {2pi}{5})(frac {4pi}{5})(frac {6pi}{5})(frac {8pi}{5})

    2.以两个相对棱的中点连线为轴,可以旋转(pi)

    3.以两个相对顶点连线为轴,可以旋转(frac {2pi}{3})(frac {4pi}{3})

    4.不旋转。

    任何一种旋转都是这里的一个,所以我们可以确定,整个旋转群里的置换就这么多。

    1.(12 / 2 * 4 = 24)

    2.(30 / 2 * 1 = 15)

    3.(20 / 2 * 2 = 20)

    4.(1)

    总共(24 + 15 + 20 + 1 = 60)个置换。

    然后套用pólya。

    考虑对于共轭的置换一起算,一共有4个共轭类,分别计算即可。

    考虑然后计算一个共轭类的答案,以第一种置换为例。

    由于这个共轭类内所有置换的所有轮换的长度都是一样的,(len = 5),由于对象数量为(60)(即rhombic hexecontahedron的菱形面数),所以共有(12)个轮换。

    考虑设计dp,(f_{i, j})表示用前(i)种颜色,对前(j)个轮换染色的方案数。

    转移方程即为:

    [f_{i, j} = sum_{k = lower} ^ {upper} f_{i - 1, j - k} inom {j}{k} ]

    其中(upper)就是轮换个数,(lower)则是颜色(i)至少用了(a_i)次需要的最少轮换数(在这个共轭类中)。这个可以(O(1))计算。

    最后,这个共轭类的答案就是(f_{n, 12} * 24),其中12是轮换个数,24是共轭类大小。

    复杂度(O(n 60 ^ 3))

    有一个要注意的地方,因为最后答案还要除掉群的大小,大小是60,可能没有逆元。所以我们一开始把模数设为(m * 60),中间都对这个东西取模(还要要用慢速乘),最后再把(60)除掉。可以用反证来证明这样做的正确性。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 60, G = 4, len[G + 1] = {0, 1, 2, 3, 5}, siz[G + 1] = {0, 1, 15, 20, 24};
    int n, m, L; ll mo, tmp, ans;
    ll a[N + 1], s[G + 1], C[N + 1][N + 1], f[N + 1][N + 1];
    inline int read () {
    	static int x;
    	scanf("%d", &x);
    	return x;
    }
    inline ll slow_mul (ll a, ll b) {
    	a %= mo, b %= mo;
    	ll ret = a * b - (ll)((long double)a * b / mo) * mo;
    	if ((ret %= mo) < 0) ret += mo;
    	return ret;
    }
    void prep () {
    	C[0][0] = 1;
    	for (int i = 1; i <= N; ++i) {
    		C[i][0] = C[i][i] = 1;
    		for (int j = 1; j < i; ++j)
    			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mo;
    	}
    }
    int main () {
    	for (int _ = read(); _; --_) {
    		n = read(), m = read(), L = 60, ans = 0, mo = (ll)m * N, prep();
    		for (int i = 1; i <= n; ++i) a[i] = read();
    		if (m == 1) {puts("0"); continue;}
    		for (int c = 1, upp, low; c <= G; ++c) {
    			upp = L / len[c];
    			memset(f, 0, sizeof f), f[0][0] = 1;
    			for (int i = 1; i <= n; ++i) {
    				low = a[i] ? (a[i] - 1) / len[c] + 1 : 0;
    				for (int j = low; j <= upp; ++j)
    					for (int k = low; k <= j; ++k)
    					f[i][j] = (f[i][j] + slow_mul(f[i - 1][j - k], C[j][k])) % mo;
    			}
    			ans = (ans + slow_mul(f[n][upp], siz[c])) % mo;
    		}
    		printf("%lld
    ", ans / N);
    	}
    	return 0;
    }
    
  • 相关阅读:
    java_oop_方法2
    POJ 3276 Face The Right Way(反转)
    POJ 3276 Face The Right Way(反转)
    POJ 2566 Bound Found(尺取法,前缀和)
    POJ 2566 Bound Found(尺取法,前缀和)
    POJ 3320 Jessica's Reading Problem(尺取法)
    POJ 3320 Jessica's Reading Problem(尺取法)
    POJ 3061 Subsequence(尺取法)
    POJ 3061 Subsequence(尺取法)
    HDU 1222 Wolf and Rabbit(欧几里得)
  • 原文地址:https://www.cnblogs.com/psimonw/p/10727413.html
Copyright © 2011-2022 走看看