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 }

 

你可能感兴趣的:(format)