zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    详解vue静态资源打包中的坑与解决方案
    vue项目构建实战基础知识:SPA理解/RESTful接口介绍/static目录配置/axios封装/打包时map文件去除
    axios踩坑记录+拦截器使用+vue cli代理跨域proxy+webpack打包部署到服务器
    vue-cli项目开发/生产环境代理实现跨域请求+webpack配置开发/生产环境的接口地址
    vue中watch的用法总结以及报错处理Error in callback for watcher "checkList"
    Vue侦听器watch
    ES6 import 引用文件夹/目录及其处理过程
    Nginx部署前端代码实现前后端分离
    使用XmlInclude解决WebService调用时无法识别子类的异常
    WebServices中Xml的序列化
  • 原文地址:https://www.cnblogs.com/CSGrandeur/p/2688142.html
Copyright © 2011-2022 走看看