题目大意

  给你一棵树,有\(n\)个点。还给你了一个整数\(k\)。

  设\(S\)为树上某些点的集合,定义\(f(S)\)为最小的包含\(S\)的联通子图的大小。

  \(n\)个点选\(k\)个点一共有\(\binom{n}{k}\)中方案,请你求出所有方案的\(f(S)\)的和\(\mod 924844033\)。

  出题人觉得这样就太简单了,他决定让你求出所有\(k=1\ldots n\)的答案。

  \(n\leq 200000\)

题解

  似乎对于每个\(k\)没办法快速求出答案。

  我们考虑一个点对所有答案的贡献。

  一个点\(x\)在这个联通子图内当且经当这\(k\)个点不在以\(x\)为根时\(x\)的子树内。

  那么贡献为\(\binom{n}{k}-\sum \binom{a_i}{k}\),其中\(a_i\)为以\(x\)为根时各个子树的大小。可以发现,计算总的贡献时每条边两端的子树大小都会被计算一次。\(\binom{n}{k}\)会被计算\(n\)次。

  设

\[b_i=
\begin{cases}
n~~~~~~~~~~(i=n)\\
num_i~~~(i\neq n)
\end{cases}
\]

其中\(num_i\)为大小为\(i\)的子树的个数

\[\begin{align}
ans_k&=\sum_{i\geq k} b_i\binom{i}{k}\\
&=\sum_{i\geq k} b_i\frac{i!}{(i-k)!k!}\\
&=\frac 1{k!}\sum_{i\geq k}b_ii!\times \frac{1}{(i-k)!}
\end{align}
\]

  这可以转化成卷积的形式

\[\begin{align}
c_{n-i}&=num_ii!\\
d_{i}&=\frac{1}{i!}\\
a_i&=\sum_{j+k=i}c_id_i\\
ans_i&=\frac{a_{n-i}}{i!}
\end{align}
\]

  时间复杂度:\(O(n\log n)\)

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<utility>
  7. #include<list>
  8. using namespace std;
  9. typedef long long ll;
  10. typedef unsigned long long ull;
  11. typedef pair<int,int> pii;
  12. const ll p=924844033;
  13. const ll g=5;
  14. ll fp(ll a,ll b)
  15. {
  16. ll s=1;
  17. while(b)
  18. {
  19. if(b&1)
  20. s=s*a%p;
  21. a=a*a%p;
  22. b>>=1;
  23. }
  24. return s;
  25. }
  26. namespace ntt
  27. {
  28. ll w1[1000010];
  29. ll w2[1000010];
  30. int rev[1000010];
  31. int n;
  32. void init()
  33. {
  34. #ifdef DEBUG
  35. n=16;
  36. #else
  37. n=524288;
  38. #endif
  39. int i;
  40. for(i=1;i<=n;i<<=1)
  41. {
  42. w1[i]=fp(g,(p-1)/i);
  43. w2[i]=fp(w1[i],p-2);
  44. }
  45. rev[0]=0;
  46. for(i=1;i<n;i++)
  47. rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
  48. }
  49. void ntt(ll *a,int t)
  50. {
  51. int i,j,k;
  52. ll u,v,w,wn;
  53. for(i=0;i<n;i++)
  54. if(rev[i]<i)
  55. swap(a[i],a[rev[i]]);
  56. for(i=2;i<=n;i<<=1)
  57. {
  58. wn=(t==1?w1[i]:w2[i]);
  59. for(j=0;j<n;j+=i)
  60. {
  61. w=1;
  62. for(k=j;k<j+i/2;k++)
  63. {
  64. u=a[k];
  65. v=a[k+i/2]*w%p;
  66. a[k]=(u+v)%p;
  67. a[k+i/2]=(u-v)%p;
  68. w=w*wn%p;
  69. }
  70. }
  71. }
  72. if(t==-1)
  73. {
  74. ll inv=fp(n,p-2);
  75. for(i=0;i<n;i++)
  76. a[i]=a[i]*inv%p;
  77. }
  78. }
  79. };
  80. ll b[1000010];
  81. ll c[1000010];
  82. ll a[1000010];
  83. ll inv[1000010];
  84. ll fac[1000010];
  85. ll ifac[1000010];
  86. int s[1000010];
  87. int n;
  88. list<int> l[200010];
  89. ll num[1000010];
  90. void dfs(int x,int fa)
  91. {
  92. s[x]=1;
  93. for(auto v:l[x])
  94. if(v!=fa)
  95. {
  96. dfs(v,x);
  97. s[x]+=s[v];
  98. num[s[v]]--;
  99. num[n-s[v]]--;
  100. }
  101. }
  102. int main()
  103. {
  104. #ifdef DEBUG
  105. freopen("b.in","r",stdin);
  106. freopen("b.out","w",stdout);
  107. #endif
  108. scanf("%d",&n);
  109. int i,x,y;
  110. for(i=1;i<=n-1;i++)
  111. {
  112. scanf("%d%d",&x,&y);
  113. l[x].push_back(y);
  114. l[y].push_back(x);
  115. }
  116. inv[0]=inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
  117. for(i=2;i<=n;i++)
  118. {
  119. inv[i]=-(p/i)*inv[p%i]%p;
  120. fac[i]=fac[i-1]*i%p;
  121. ifac[i]=ifac[i-1]*inv[i]%p;
  122. }
  123. dfs(1,0);
  124. num[n]=n;
  125. for(i=0;i<=n;i++)
  126. b[i]=num[n-i]*fac[n-i]%p;
  127. for(i=0;i<=n;i++)
  128. c[i]=ifac[i];
  129. ntt::init();
  130. ntt::ntt(b,1);
  131. ntt::ntt(c,1);
  132. for(i=0;i<ntt::n;i++)
  133. a[i]=b[i]*c[i]%p;
  134. ntt::ntt(a,-1);
  135. for(i=1;i<=n;i++)
  136. {
  137. ll ans=a[n-i]*ifac[i]%p;
  138. ans=(ans+p)%p;
  139. printf("%lld\n",ans);
  140. }
  141. return 0;
  142. }

【AGC005F】Many Easy Problems FFT 容斥原理的更多相关文章

  1. AGC005F Many Easy Problems(NTT)

    先只考虑求某个f(k).考虑转换为计算每条边的贡献,也即该边被所选连通块包含的方案数.再考虑转换为计算每条边不被包含的方案数.这仅当所选点都在该边的同一侧.于是可得f(k)=C(n,k)+ΣC(n,k ...

  2. 【AtCoder】AGC005F - Many Easy Problems

    题解 我们把一个点的贡献转化为一条边的贡献,因为边的数量是点的数量-1,最后再加上选点方案数\(\binom{n}{k}\)即可 一条边的贡献是\(\binom{n}{k} - \binom{a}{k ...

  3. [AGC005F] Many Easy Problems

    link 题意简述 给定一颗无根树,对于所有大小为 $i$ 的点集,求出能够包含它的所有联通块之和,定义为 $f_i$ ,答案对 $924844033$ 取模. $n\leq 2\times 10^5 ...

  4. 解题:AT2064 Many Easy Problems&EXNR #1 T3 两开花

    题面 两道题比较像,放在一起写了,后者可以看成前者的加强版 (sto ztb orz) 先看AT那道题 考虑计算每个点的贡献,用容斥计算:每个点没有贡献当且仅当选的所有点都在以他为根时的一个子节点的子 ...

  5. Codeforces 913D - Too Easy Problems

    913D - Too Easy Problems 思路:二分check k 代码: #include<bits/stdc++.h> using namespace std; #define ...

  6. 【AtCoder】AGC005 F - Many Easy Problems 排列组合+NTT

    [题目]F - Many Easy Problems [题意]给定n个点的树,定义S为大小为k的点集,则f(S)为最小的包含点集S的连通块大小,求k=1~n时的所有点集f(S)的和取模92484403 ...

  7. 【CodeForces】913 D. Too Easy Problems

    [题目]D. Too Easy Problems [题意]给定n个问题和总时限T,每个问题给定时间ti和限制ai,当解决的问题数k<=ai时问题有效,求在时限T内选择一些问题解决的最大有效问题数 ...

  8. AtcoderGrandContest 005 F. Many Easy Problems

    $ >AtcoderGrandContest \space 005 F.  Many Easy Problems<$ 题目大意 : 有一棵大小为 \(n\) 的树,对于每一个 \(k \i ...

  9. 【bzoj3771】Triple FFT+容斥原理

    题目描述 樵夫的每一把斧头都有一个价值,不同斧头的价值不同.总损失就是丢掉的斧头价值和. 他想对于每个可能的总损失,计算有几种可能的方案. 注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视 ...

随机推荐

  1. 小菜鸡儿的第三次OO博客

    规格化设计历史 规格化设计的历史目前网上的资料并不多,百度谷歌必应也表示无能为力...... 在这里结合现实情况讲一讲自己对程序规格化的理解,首先代码规格化对代码的影响是间接的,或许它不能让你代码里面 ...

  2. Python-Requests库详解

    查看一下是否安装requests库 什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关 ...

  3. C. Prefixes and Suffixes

    链接 [https://codeforces.com/contest/1092/problem/C] 题意 给你某个字符串的长度n,再给你2*n-2个前缀或者后缀 让你判断那些是前缀那些是后缀 关键是 ...

  4. Dapper.NET

    关于Dapper.NET的相关论述   年少时,为何不为自己的梦想去拼搏一次呢?纵使头破血流,也不悔有那年少轻狂.感慨很多,最近事情也很多,博客也很少更新了,毕竟每个人都需要为自己的生活去努力. 最近 ...

  5. 使用ajax请求后端程序时,关于目标程序路径问题

    这里涉及到和PHP中类似的问题,有待更新!!!

  6. CSS小东西

    1.表格列自动均分 table-layout:fixed; 2.单元格内容自动换行 word-wrap:break-word;

  7. CSS响应式布局实例

    <style type="text/css">        body{            margin:0 auto;            min-width: ...

  8. 移动端tap事件,消除300毫秒延迟

    引用这个之前,要讲一下首先我是用了webpack技术,所以你的项目如果没有用到这个的话,最好不要用这个技术,当然想用也可以,改下代码也可以用. 下面的代码直接复制就可以用啦. ( function(e ...

  9. [转帖]wifi 4G 和 蓝牙的区别

    作者:沈万马链接:https://www.zhihu.com/question/64739486/answer/225227838来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  10. StringTokenizer

    StringTokenizer是一个用来分隔String的应用类,相当于VB的split函数. 1.构造函数 public StringTokenizer(String str) public Str ...