HDU 6036 Division Game

考虑每堆石头最多操作 $ \sum e $ 次,考虑设 $ f(x) $ 表示某一堆石头(最开始都是一样的)操作 $ x $ 次后变成了 $ 1 $ 的方案数量。

明显的,某一堆石头操作了 $ x $ 次后仍然没有变成 $ 1 $ 的方案数量是 $ f(x+1) $。因为最后一次操作必然是把石头从某个数字拿到1。(这个算个小trick吧?)

那么对于第 \(k\) 堆石头答案就是 $ f^{k-1}(x+1) f^{m-i+1}(x) $

因为前 $ k - 1 $ 堆石头进行了 $ x $ 次拿石头的操作还没变成 $ 1 $,而从 $ k $ 后面所有的石头都进行 $ x - 1 $ 次操作并且没变成 $ 1 $ ,而第 $ k $ 堆石头是变成了 $ 1 $ 的。

然后考虑怎么计算 $ f(x) $

相当于我们有 $ m $ 种球每种 $ e_i $ 个放进 $ x $ 个不同的盒子里面,并且最后不能有盒子是空的

如果可以有盒子是空的,这个会比较好算,对每种球分开考虑,并且分别用插板法,最后乘法原理答案是 $ f'(x)=\displaystyle \prod_{i=1}^m\binom{e_i+x-1}{x-1} $

但是这个还不是答案,因为可以为空,不能为空可以考虑容斥,总方案数减去至少一个为空加上至少两个为空... 容斥系数是 $ (-1)^{t} $ 其中 $ t $ 代表至少有 $ t $ 个位置是空的。

$ f(x) = \displaystyle\sum_{i=0}^x (-1)^{x-i}f'(i)\binom{x}{i} $

$ f'(x) $ 化一下发现很容易求所以 $ f(x) $ 就可以NTT辣

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <cstring>
  5. #define ll long long
  6. using namespace std;
  7. #define P 985661441
  8. #define MAXN (1 << 19) + 13
  9. int m , k;
  10. int a[MAXN];
  11. int Pow(int x,int y) {
  12. int res=1;
  13. while(y) {
  14. if(y&1) res=res*(ll)x%P;
  15. x=x*(ll)x%P,y>>=1;
  16. }
  17. return res;
  18. }
  19. int wn[2][MAXN];
  20. void getwn(int l) {
  21. for(int i=1;i<(1<<l);i<<=1) {
  22. int w0=Pow(3,(P-1)/(i<<1)),w1=Pow(3,P-1-(P-1)/(i<<1));
  23. wn[0][i]=wn[1][i]=1;
  24. for(int j=1;j<i;++j)
  25. wn[0][i+j]=wn[0][i+j-1]*(ll)w0%P,
  26. wn[1][i+j]=wn[1][i+j-1]*(ll)w1%P;
  27. }
  28. }
  29. int rev[MAXN];
  30. void getr(int l) { for(int i=1;i<(1<<l);++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1); }
  31. void NTT(int *A,int len,int f) {
  32. for(int i=0;i<len;++i) if(rev[i]<i) swap(A[i],A[rev[i]]);
  33. for(int l=1;l<len;l<<=1)
  34. for(int i=0;i<len;i+=(l<<1))
  35. for(int k=0;k<l;++k) {
  36. int t1=A[i+k],t2=A[i+l+k]*(ll)wn[f][l+k]%P;
  37. A[i+k]=(t1+t2)%P;
  38. A[i+l+k]=(t1-t2+P)%P;
  39. }
  40. if( f == 1 ) for(int inv=Pow(len,P-2),i=0;i<len;++i) A[i]=A[i]*(ll)inv%P;
  41. }
  42. int J[MAXN] , invJ[MAXN] , p[MAXN];
  43. int kase = 0;
  44. int pp[20] , E[20] , F[MAXN] , n;
  45. signed main() {
  46. J[0] = invJ[0] = 1;
  47. for( int i = 1 ; i < MAXN ; ++ i )
  48. J[i] = 1ll * J[i - 1] * i % P , invJ[i] = Pow( J[i] , P - 2 );
  49. while( cin >> m >> k ) {
  50. memset( p , 0 , sizeof p ) , memset( F , 0 , sizeof F );
  51. n = 1;
  52. for( int i = 1 ; i <= m ; ++ i ) {
  53. scanf("%d%d",&pp[i],&E[i]);
  54. n += E[i];
  55. }
  56. p[0] = 1;
  57. for( int i = 1 ; i <= n ; ++ i ) {
  58. F[i] = invJ[i] , p[i] = ( ( ( i & 1 ) ? -1 : 1 ) * invJ[i] + P ) % P;
  59. for( int j = 1 ; j <= m ; ++ j )
  60. F[i] = 1ll * F[i] * J[E[j] + i - 1] % P * invJ[i - 1] % P * invJ[E[j]] % P;
  61. }
  62. // cout << F[2] << endl;
  63. int len = 1 , l = 0;
  64. while( len <= n * 2 ) len <<= 1 , ++ l;
  65. getr( l ) , getwn( l );
  66. NTT( F , len , 0 ) , NTT( p , len , 0 );
  67. for( int i = 0 ; i < len ; ++ i ) F[i] = 1ll * F[i] * p[i] % P;
  68. NTT( F , len , 1 );
  69. for( int i = 0 ; i < len ; ++ i ) F[i] = 1ll * F[i] * J[i] % P;
  70. // cout << F[2] << endl;
  71. printf("Case #%d: ",++kase);
  72. for( int i = 1 ; i <= k ; ++ i ) {
  73. int res = 0;
  74. for( int x = 0 ; x < n ; ++ x )
  75. res = ( res + 1ll * Pow( F[x + 1] , i - 1 ) * Pow( F[x] , k - i + 1 ) % P ) % P ;
  76. printf("%d",res);
  77. if( i != k ) putchar(' ');
  78. }
  79. puts("");
  80. }
  81. }

HDU 6036 Division Game的更多相关文章

  1. HDU 6036 - Division Game | 2017 Multi-University Training Contest 1

    /* HDU 6036 - Division Game [ 组合数学,NTT ] | 2017 Multi-University Training Contest 1 题意: k堆石子围成一个圈,数量 ...

  2. hdu 3480 Division(斜率优化DP)

    题目链接:hdu 3480 Division 题意: 给你一个有n个数的集合S,现在让你选出m个子集合,使这m个子集合并起来为S,并且每个集合的(max-min)2 之和要最小. 题解: 运用贪心的思 ...

  3. 【HDU 6036】Division Game (NTT+数学)

    多校1 1004 HDU-6036 Division Game 题意 有k堆石头(0~k-1),每堆n个.\(n=\prod_{i=0}^{m}p_i^{e_i}\).\(0\le m,k \le 1 ...

  4. HDU 3480 Division(斜率优化+二维DP)

    Division Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 999999/400000 K (Java/Others) Tota ...

  5. HDU 3480 - Division - [斜率DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480 Time Limit: 10000/5000 MS (Java/Others) Memory L ...

  6. HDU 3480 Division(斜率DP裸题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480 题目大意:将n个数字分成m段,每段价值为(该段最大值-该段最小值)^2,求最小的总价值. 解题思 ...

  7. hdu 2615 Division(暴力)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2615 题解:挺简单的暴力枚举,小小的分治主要是看没人写题解就稍微写一下 #include <io ...

  8. HDU 3480 division

    题目大意:一个有n个数的集合,现在要求将他分成m+1个子集,对子集i设si表示该集合中最大数与最小数的差的平方.求所有si的和的最小值.n<=10000,m<=5000. 分析:最优解的m ...

  9. hdu 3480 Division(四边形不等式优化)

    Problem Description Little D is really interested in the theorem of sets recently. There’s a problem ...

随机推荐

  1. vue3.x自定义组件双向数据绑定v-model

    vue2.x 语法 在 2.x 中,在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件: <ChildComponent v-model="pag ...

  2. luogu P2746 [USACO5.3]校园网Network of Schools 题解

    前言: 火星题... 但是我调了半天,最后看了题解才明白. Wtcl 解析: 显然先缩个点. 第一问,就是问多少入度为0的点. 第二问,抽象一下就是要添加一些边,让一个DAG变成一个SCC,求最小边数 ...

  3. 【转】PLI是什么以及怎么用

    programmable language interface 这里就说给verilog用的一些系统函数,还是无双大大的帖子 首先介绍了怎么让你自己写的pli系统函数在ncverilog里面可以成功调 ...

  4. poj 1129 Channel Allocation(图着色,DFS)

    题意: N个中继站,相邻的中继站频道不得相同,问最少需要几个频道. 输入输出: Sample Input 2 A: B: 4 A:BC B:ACD C:ABD D:BC 4 A:BCD B:ACD C ...

  5. 并发编程从零开始(十四)-Executors工具类

    并发编程从零开始(十四)-Executors工具类 12 Executors工具类 concurrent包提供了Executors工具类,利用它可以创建各种不同类型的线程池 12.1 四种对比 单线程 ...

  6. Java线程的三种实现方法

    Java多线程详解 线程简介 多任务,多线程 多任务情况中,虽然可以完成,但是实际上,多任务的完成是由一个一个小任务的完成来实现的,也就是说在执行多任务时,不是同时执行多个任务,而是一个时间段内只完成 ...

  7. Element - 日期禁用集合(持续更新)

    当前日期之前的日期禁用 <el-date-picker v-model="form.startTime" type="date" placeholder= ...

  8. 近期业务大量突增微服务性能优化总结-4.增加对于同步微服务的 HTTP 请求等待队列的监控

    最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...

  9. redis开外网访问

    Redis: 注释掉bind 127.0.0.1可以使所有的ip访问redis 若是想指定多个ip访问,但并不是全部的ip访问,可以bind protected-mode no /etc/init.d ...

  10. 寒武纪加速平台(MLU200系列) 摸鱼指南(一)--- 基本概念及相关介绍

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...