题目链接  2017 CCPC Hangzhou Problem G

题意描述很清晰。

考虑每个家庭有且仅有$k$对近亲的方案数:

$C(a, k) * C(b, k) * k!$

那么如果在第$1$个家庭里面选出$k_{1}$对近亲,在第$2$个家庭里面选出$k_{2}$对近亲......在第$n$个家庭里面选出$k_{n}$对近亲,

剩下那些人自由组合的话,那么最后这种方案至少会有$∑k$对近亲。

说是至少,因为同一个家庭里面没被强行选择的男女还是可能被组到了一起。

那么考虑如何求至少有$k$对近亲的方案数。

构造$n$个多项式,对于每个家庭,这个多项式为

$c_{0} + c_{1}x + c_{2}x^{2} + c_{3}x^{3} + c_{4}x^{4} + ... + c_{p}x^{p}$, $p = min(a, b)$

其中$c_{i}$这个系数为在这个家庭里面选出$i$对近亲的方案数。

那么只要把这$n$个多项式乘起来,得到的结果里面$x^{k}$的系数就是至少有$k$对近亲的方案数。

把$n$个多项式求出来用分治NTT即可,我用了启发式合并。

因为是至少,所以还要考虑容斥。

最后的答案就是$(-1)^{k}a_{k} * (m - k)!$,$m$为总人数

时间复杂度$O(nlog^{2}n)$

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. #define rep(i, a, b) for (int i(a); i <= (b); ++i)
  6. #define dec(i, a, b) for (int i(a); i >= (b); --i)
  7. #define MP make_pair
  8. #define fi first
  9. #define se second
  10.  
  11. typedef long long LL;
  12.  
  13. const int N = 1e5 + 10;
  14. const LL mod = 998244353;
  15. const LL g = 3;
  16.  
  17. vector <LL> v[N << 1];
  18. LL x1[N << 1], x2[N << 1];
  19. LL fac[N];
  20. LL ans, flag;
  21. int T;
  22. int n, all, cnt;
  23. int sz;
  24.  
  25. inline LL Pow(LL a, LL b, LL mod){
  26. LL ret(1);
  27. for (; b; b >>= 1, (a *= a) %= mod) if (b & 1) (ret *= a) %= mod;
  28. return ret;
  29. }
  30.  
  31. inline LL C(LL n, LL m){ return m > n ? 0 : fac[n] * Pow(fac[m] * fac[n - m] % mod, mod - 2, mod) % mod; }
  32.  
  33. struct cmp{
  34. bool operator ()(int a, int b){
  35. return v[a].size() > v[b].size();
  36. }
  37. };
  38.  
  39. priority_queue <LL, vector <LL>, cmp> q;
  40.  
  41. void change(LL y[], int len){
  42. for (int i = 1, j = len / 2; i < len - 1; i++){
  43. if (i < j) swap(y[i], y[j]);
  44. int k = len / 2;
  45. while (j >= k){
  46. j -= k;
  47. k /= 2;
  48. }
  49. if (j < k) j += k;
  50. }
  51. }
  52.  
  53. void ntt(LL y[], int len, int on){
  54. change(y, len);
  55. for (int h = 2; h <= len; h <<= 1){
  56. LL wn = Pow(g, (mod - 1) / h, mod);
  57. if (on == -1) wn = Pow(wn, mod - 2, mod);
  58. for (int j = 0; j < len; j += h){
  59. LL w = 1ll;
  60. for (int k = j; k < j + h / 2; k++){
  61. LL u = y[k];
  62. LL t = w * y[k + h / 2] % mod;
  63. y[k] = (u + t) % mod;
  64. y[k + h / 2] = (u - t + mod) % mod;
  65. w = w * wn % mod;
  66. }
  67. }
  68. }
  69.  
  70. if (on == -1){
  71. LL t = Pow(len, mod - 2, mod);
  72. rep(i, 0, len - 1) y[i] = y[i] * t % mod;
  73. }
  74. }
  75.  
  76. void mul(vector <LL> &a, vector <LL> &b, vector <LL> &c){
  77. int len = 1;
  78. int sz1 = a.size(), sz2 = b.size();
  79.  
  80. while (len <= sz1 + sz2 - 1) len <<= 1;
  81.  
  82. rep(i, 0, sz1 - 1) x1[i] = a[i];
  83. rep(i, sz1, len) x1[i] = 0;
  84.  
  85. rep(i, 0, sz2 - 1) x2[i] = b[i];
  86. rep(i, sz2, len) x2[i] = 0;
  87.  
  88. ntt(x1, len, 1);
  89. ntt(x2, len, 1);
  90.  
  91. rep(i, 0, len - 1) x1[i] = x1[i] * x2[i];
  92.  
  93. ntt(x1, len, -1);
  94.  
  95. vector <LL>().swap(c);
  96. rep(i, 0, sz1 + sz2 - 2) c.push_back(x1[i]);
  97. }
  98.  
  99. int main(){
  100.  
  101. fac[0] = 1;
  102. rep(i, 1, 1e5 + 3) fac[i] = fac[i - 1] * i % mod;
  103.  
  104. scanf("%d", &T);
  105.  
  106. while (T--){
  107. scanf("%d", &n);
  108. rep(i, 0, n + 1) vector <LL>().swap(v[i]);
  109.  
  110. while (!q.empty()) q.pop();
  111.  
  112. all = 0;
  113.  
  114. rep(i, 1, n){
  115. int x, y;
  116. scanf("%d%d", &x, &y);
  117. v[i].resize(min(x, y) + 1);
  118. rep(k, 0, min(x, y)) v[i][k] = C(x, k) * C(y, k) % mod * fac[k] % mod;
  119. q.push(i);
  120. all += x;
  121. }
  122.  
  123. cnt = n;
  124. rep(i, 1, n - 1){
  125. int x = q.top(); q.pop();
  126. int y = q.top(); q.pop();
  127.  
  128. mul(v[x], v[y], v[++cnt]);
  129.  
  130. vector <LL>().swap(v[x]);
  131. vector <LL>().swap(v[y]);
  132.  
  133. q.push(cnt);
  134. }
  135.  
  136. ans = 0;
  137. flag = 1;
  138. sz = (int)v[cnt].size();
  139. rep(i, 0, sz - 1){
  140. ans = ans + flag * fac[all - i] % mod * v[cnt][i] % mod;
  141. ans = (ans + mod) % mod;
  142. flag = -flag;
  143. }
  144.  
  145. printf("%lld\n", ans);
  146. }
  147.  
  148. return 0;
  149. }

HDU 6270 Marriage (2017 CCPC 杭州赛区 G题,生成函数 + 容斥 + 分治NTT)的更多相关文章

  1. HDU - 6513 Reverse It (SYSU校赛C题)(组合数学+容斥)

    题目链接 题意:给定一个n*m的矩阵,可以选择至多两个子矩阵将其反转,求能形成多少种不同的矩阵. 任选一个矩阵有$C_{n+1}^{2}C_{m+1}^{2}$种方法,任选两个不同的矩阵有$C_{C_ ...

  2. HDU 6271 Master of Connected Component(2017 CCPC 杭州 H题,树分块 + 并查集的撤销)

    题目链接  2017 CCPC Hangzhou Problem H 思路:对树进行分块.把第一棵树分成$\sqrt{n}$块,第二棵树也分成$\sqrt{n}$块.    分块的时候满足每个块是一个 ...

  3. HDU 6268 Master of Subgraph (2017 CCPC 杭州 E题,树分治 + 树上背包)

    题目链接  2017 CCPC Hangzhou  Problem E 题意  给定一棵树,每个点有一个权值,现在我们可以选一些连通的点,并且把这点选出来的点的权值相加,得到一个和. 求$[1, m] ...

  4. HDU 6240 Server(2017 CCPC哈尔滨站 K题,01分数规划 + 树状数组优化DP)

    题目链接  2017 CCPC Harbin Problem K 题意  给定若干物品,每个物品可以覆盖一个区间.现在要覆盖区间$[1, t]$. 求选出来的物品的$\frac{∑a_{i}}{∑b_ ...

  5. 2017 CCPC 杭州 流水账

    day0: 队内训练ccpc 秦皇岛,敝校自己出的题,感觉一个星期没怎么写代码,手生得很,不出意料被打飞了. day1 (热身赛): 热身赛还算顺利,A题看有的队几分钟就草过去了,还以为又是西安ICP ...

  6. HDU 4778 Gems Fight! (2013杭州赛区1009题,状态压缩,博弈)

    Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)T ...

  7. HDU 4771 Stealing Harry Potter's Precious (2013杭州赛区1002题,bfs,状态压缩)

    Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 ...

  8. HDU 4770 Lights Against Dudely (2013杭州赛区1001题,暴力枚举)

    Lights Against Dudely Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  9. 2017 CCPC 杭州 HDU6265B 积性函数

    题目链接 http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf B题 数论题      h(n)=∑ d|n φ(d) × ...

随机推荐

  1. Android如何实现毛玻璃效果之Android高级模糊技术

    自从iOS系统引入了Blur效果,也就是所谓的毛玻璃.模糊化效果,磨砂效果,各大系统就开始竞相模仿,这是怎样的一个效果呢,我们先来看一下,如下面的图片: 效果我们知道了,如何在Android中实现呢, ...

  2. 关于mac ox node安装报 npm ERR! registry error parsing json

    想安装grunt 遇到2个问题 让npm重新设置一下config: npm config set registry http://registry.cnpmjs.org 然后还报 npm ERR! E ...

  3. Python全栈工程师(运算符、if)

    ParisGabriel       Python 入门基础   比较运算符:< 小于<= 小于等于> 大于>= 大于等于== 等于!= 不等于 语法: 表达式1>表达式 ...

  4. 孤荷凌寒自学python第四十三天python 的线程同步之Queue对象

     孤荷凌寒自学python第四十三天python的线程同步之Queue对象 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Queue对象是直接操作队列池的对象,队列中可以存放多种对象,当然也 ...

  5. 融合模型Aggregation

    从一堆弱分类器融合得到强分类器. 比如假设现在你只能水平或竖直线分割,那么无论如何都分不好,但是假设组合三次分割,就会得到如图所示的一个较好的分割线. 再比如,PLA 融合后有large margin ...

  6. php数组循环的三种方式

    PHP 的遍历数组的三种方式:for循环.foreach循环.while.list().each()组合循环 PHP当中数组分为:索引数组[转换成json是数组]和关联数组[转换成json是对象] f ...

  7. [ecmagent][redis学习][1初识redis] redis安装+redis快速教程+python操作redis

    # redis安装 # redis安装教程 -- 服务器(ubuntu)安装redis服务 sudo apt-get install redis-server -- 源码安装 -- $ wget ht ...

  8. Application_Start事件中用Timer做一个循环任务

    protected void Application_Start(object sender, EventArgs e) { System.Timers.Timer timer = new Syste ...

  9. Scala 基础(3)—— 基础类型和基础操作

    1. Scala 的一些基础类型 Scala 提供了 8 种基础类型,对应 Java 的 8 种基本数据类型. 其中包括: 整数类型:Byte, Short, Int, Long, Char 浮点类型 ...

  10. linxu安装方式

    安装Linux操作系统的5种方法以及心得这几天没有调别的东西,想起自己还不太会在没有安装光盘的时候安装Linux,于是试了一下Linux的五种安装方法,下面是我的一些 篇一:安装Linux操作系统的5 ...