HDU4290 Counting Formations

Staginner剽悍地抽象出了数学模型并推出了各项数据,万事俱备只欠东风,可惜最后一步推错了,比赛时候这题没过。。

插板法组合数对应了不同icon的分配方案。

每种分配方案又对应了很多种摆放方案。

假设有s种分配方案,x[1]~x[s]分别对应了每种分配方案的摆放方案,可通过DP求得∑x 。

也可求得∑(x^2),∑(x^3)...

设M[p] = ∑(x^p)。

设S[p] = x[i1]*x[i2]*x[i3]...*x[ip],i1~ip为互不相同的1~s的序列。

题目所给棋盘是N行,我们求的就是S[N] * N!

——————————分割线——————————

以上是Staginner得到的数据与结论,详细的推导他应该会写博客的。

 

接下来要解决的就是如何用M[1]~M[p]来推S[p],没想到被我一推一推推出来了。

首先S[1] == M[1]

S[1] * M[1]的结果是两两不同x的积和相同x的平方项,那么去掉平方项就是S[2]的若干倍。

在S[1] * M[1]的过程中每一个S[2]的项都由两个组成它的x乘得一次,所以这个“若干倍”是2。

S[2] = (S[1] * M[1] - M[2]) / 2

递推过去,最终

S[p] = (S[p - 1] * M[1] - S[p - 2] * M[2] + S[p - 3] * M[3] - S[p - 4] * M[4] ....) / p

这样就得到了S[N]。

中间该取模取模,该求逆元求逆元,就OK了。

 

代码是在Staginner代码上改的。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define MAXD 33
 4 #define MOD 1000000007
 5 typedef __int64 LL;
 6 int N, M, K;
 7 LL C[MAXD][MAXD][MAXD], f[MAXD][MAXD], X[MAXD], S[MAXD];
 8 LL fac(LL a, int n)
 9 {
10     int i;
11     LL ans = 1;
12     for(i = 0; i < n; i ++) ans = ans * a % MOD;
13     return ans;
14 }
15 void exgcd(LL a, LL b, LL &x, LL &y)
16 {
17     if(b == 0) x = 1, y = 0;
18     else exgcd(b, a % b, y, x), y -= x * (a / b);
19 }
20 LL getinv(LL a)
21 {
22     LL x, y;
23     exgcd(a, MOD, x, y);
24     x %= MOD;
25     if(x < 0) x += MOD;
26     return x;
27 }
28 void prepare()
29 {
30     int i, j, t;
31     memset(C, 0, sizeof(C));
32     C[1][0][0] = 1;
33     for(i = 1; i <= 32; i ++)
34     {
35         C[1][i][0] = 1;
36         for(j = 1; j <= i; j ++)
37             C[1][i][j] = (C[1][i - 1][j] + C[1][i - 1][j - 1]) % MOD;
38     }
39     for(t = 2; t <= 32; t ++)
40         for(i = 0; i <= 32; i ++)
41             for(j = 0; j <= 32; j ++)
42                 C[t][i][j] = fac(C[1][i][j], t);
43 }
44 void solve()
45 {
46     int i, j, k, t;
47     LL ans;
48     for(t = 1; t <= N; t ++)
49     {
50         memset(f, 0, sizeof(f)), f[0][0] = 1;
51         for(i = 1; i <= K; i ++)
52             for(j = 0; j <= M; j ++)
53                 for(k = 0; k <= j; k ++)
54                     f[i][j] = (f[i][j] + f[i - 1][k] * C[t][M - k][j - k]) % MOD;
55         X[t] = f[K][M];
56     }
57     S[0] = 1, S[1] = X[1];
58     for(i = 2; i <= N; i ++)
59     {
60         S[i] = 0;
61         for(j = 1; j <= i; j ++)
62         {
63             if(j & 1) S[i] = (S[i] + S[i - j] * X[j] + MOD) % MOD;
64             else S[i] = (S[i] - S[i - j] * X[j] + MOD) % MOD;
65         }
66         S[i] = S[i] * getinv(i) % MOD;
67     }
68     ans = S[N];
69     for(i = 2; i <= N; i ++) ans = ans * i % MOD;
70     if(ans < 0) ans += MOD;
71     printf("%I64d\n", ans);
72 }
73 int main()
74 {
75     prepare();
76     while(scanf("%d%d%d", &N, &M, &K) == 3)
77         solve();
78     return 0;
79 }

 

posted @ 2012-09-17 02:13  CSGrandeur  阅读(1310)  评论(5编辑  收藏  举报