AtCoder - 2064 Many Easy Problems
Problem Statement
One day, Takahashi was given the following problem from Aoki:
- You are given a tree with N vertices and an integer K. The vertices are numbered 1 through N. The edges are represented by pairs of integers (ai,bi).
- For a set S of vertices in the tree, let f(S) be the minimum number of the vertices in a subtree of the given tree that contains all vertices in S.
- There are
ways to choose K vertices from the trees. For each of them, let S be the set of the chosen vertices, and find the sum of f(S) over all
ways.
- Since the answer may be extremely large, print it modulo 924844033(prime).
Since it was too easy for him, he decided to solve this problem for all K=1,2,…,N.
Constraints
- 2≦N≦200,000
- 1≦ai,bi≦N
- The given graph is a tree.
Input
The input is given from Standard Input in the following format:
- N
- a1 b1
- a2 b2
- :
- aN−1 bN−1
Output
Print N lines. The i-th line should contain the answer to the problem where K=i, modulo 924844033.
Sample Input 1
- 3
- 1 2
- 2 3
Sample Output 1
- 3
- 7
- 3
The diagram above illustrates the case where K=2. The chosen vertices are colored pink, and the subtrees with the minimum number of vertices are enclosed by red lines.
Sample Input 2
- 4
- 1 2
- 1 3
- 1 4
Sample Output 2
- 4
- 15
- 13
- 4
Sample Input 3
- 7
- 1 2
- 2 3
- 2 4
- 4 5
- 4 6
- 6 7
Sample Output 3
- 7
- 67
- 150
- 179
- 122
- 45
- 7
- 考虑每条边的贡献,对于k==i的答案显然会贡献 C(n,i) - C(s,i) - C(n-s,i) ,其中s是边一端的子树大小。
这玩意暴力算显然是 O(N^2) 的,想一想还可以怎么优化。- 显然每条边的第一项 C(n,i) 是常量,我们最后对于每个i加上即可;
后面的组合数可以拆成 阶乘和阶乘的逆的乘积的形式,所以我们就可以构造两个多项式:
A = ∑ cnt[s] * x^s (cnt[s] 是 子树大小为s的子树个数)
B = Σ 1/(i!) * x^(-i)
这两个多项式卷出来就可以得到每个k==i的答案(别忘了每个位置再乘一个阶乘的逆元)- (只有我一个人被模数坑了吗QWQ)
- /*
- 对于一条把树分成s和n-s的边
- C(s,k) -> s! / k! / (s-k)!
- C(n-s,k) -> (n-s)! / k! / (n-s-k)!
- */
- #include<bits/stdc++.h>
- #define ll long long
- using namespace std;
- const int maxn=600005,ha=924844033,root=5;
- inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
- inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
- inline int ksm(int x,int y){
- int an=1;
- for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
- return an;
- }
- int jc[maxn+5],ni[maxn+5],n,m,ans,to[maxn*2],ne[maxn*2],num,inv;
- int a[maxn+5],b[maxn+5],r[maxn+5],siz[maxn+5],hd[maxn],N,l,INV;
- inline void addline(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
- inline int C(int x,int y){ return x<y?0:jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha;}
- inline void init(){
- jc[0]=1;
- for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha;
- ni[maxn]=ksm(jc[maxn],ha-2);
- for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
- }
- void dfs(int x,int fa){
- siz[x]=1;
- for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa) dfs(to[i],x),siz[x]+=siz[to[i]];
- if(x!=1) ADD(a[siz[x]],jc[siz[x]]),ADD(a[n-siz[x]],jc[n-siz[x]]);
- }
- inline void NTT(int *c,int f){
- for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]);
- for(int i=1;i<N;i<<=1){
- int omega=ksm(f==1?root:inv,(ha-1)/(i<<1));
- for(int j=0,P=i<<1;j<N;j+=P){
- int now=1;
- for(int k=0;k<i;k++,now=now*(ll)omega%ha){
- int x=c[j+k],y=c[j+k+i]*(ll)now%ha;
- c[j+k]=add(x,y);
- c[j+k+i]=add(x,ha-y);
- }
- }
- }
- if(f==-1) for(int i=0;i<N;i++) c[i]=c[i]*(ll)INV%ha;
- }
- inline void solve(){
- dfs(1,1);
- for(int i=0;i<n;i++) b[n-i]=ni[i];
- for(N=1;N<=(2*n);N<<=1) l++;
- for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
- NTT(a,1),NTT(b,1);
- for(int i=0;i<N;i++) a[i]=a[i]*(ll)b[i]%ha;
- INV=ksm(N,ha-2),NTT(a,-1);
- for(int i=1;i<=n;i++) a[i+n]=add(ha-a[i+n]*(ll)ni[i]%ha,C(n,i)*(ll)n%ha);
- }
- int main(){
- // freopen("data.in","r",stdin);
- // freopen("data.out","w",stdout);
- init(),inv=ksm(5,ha-2);
- scanf("%d",&n);
- int uu,vv;
- for(int i=1;i<n;i++) scanf("%d%d",&uu,&vv),addline(uu,vv),addline(vv,uu);
- solve();
- for(int i=1;i<=n;i++) printf("%d\n",a[i+n]);
- return 0;
- }
AtCoder - 2064 Many Easy Problems的更多相关文章
- 【AtCoder】AGC005 F - Many Easy Problems 排列组合+NTT
[题目]F - Many Easy Problems [题意]给定n个点的树,定义S为大小为k的点集,则f(S)为最小的包含点集S的连通块大小,求k=1~n时的所有点集f(S)的和取模92484403 ...
- 解题:AT2064 Many Easy Problems&EXNR #1 T3 两开花
题面 两道题比较像,放在一起写了,后者可以看成前者的加强版 (sto ztb orz) 先看AT那道题 考虑计算每个点的贡献,用容斥计算:每个点没有贡献当且仅当选的所有点都在以他为根时的一个子节点的子 ...
- Codeforces 913D - Too Easy Problems
913D - Too Easy Problems 思路:二分check k 代码: #include<bits/stdc++.h> using namespace std; #define ...
- 【CodeForces】913 D. Too Easy Problems
[题目]D. Too Easy Problems [题意]给定n个问题和总时限T,每个问题给定时间ti和限制ai,当解决的问题数k<=ai时问题有效,求在时限T内选择一些问题解决的最大有效问题数 ...
- AtcoderGrandContest 005 F. Many Easy Problems
$ >AtcoderGrandContest \space 005 F. Many Easy Problems<$ 题目大意 : 有一棵大小为 \(n\) 的树,对于每一个 \(k \i ...
- 【AtCoder】AGC005F - Many Easy Problems
题解 我们把一个点的贡献转化为一条边的贡献,因为边的数量是点的数量-1,最后再加上选点方案数\(\binom{n}{k}\)即可 一条边的贡献是\(\binom{n}{k} - \binom{a}{k ...
- AtCoder Grand Contest 005F - Many Easy Problems
$n \leq 200000$的树,从树上选$k$个点的一个方案会对$Ans_k$产生大小为“最小的包括这$k$个点的连通块大小”的贡献.求每个$Ans_k$.膜924844033. 看每个点对$An ...
- [题解] Atcoder AGC 005 F Many Easy Problems NTT,组合数学
题目 观察当k固定时答案是什么.先假设每个节点对答案的贡献都是\(\binom{n}{k}\),然后再减掉某个点没有贡献的选点方案数.对于一个节点i,它没有贡献的方案数显然就是所有k个节点都选在i连出 ...
- Codeforces B. Too Easy Problems
题目描述: time limit per test 2 seconds memory limit per test 256 megabytes input standard input output ...
随机推荐
- 编译 openssl 0.9.8zc 出现 error C2220: warning treated as error - no 'object' file generated
remove the /WX option from CFLAG
- 复选框 checkbox 选中事件
项目中用的jquery-1.11 今天需要检测一个checkbox的选中状态,想当然的用 .attr("checked") ,结果发现,无论是否选中,这个值都是 undefined ...
- 转:深入理解javascript原型和闭包系列
转自:深入理解javascript原型和闭包系列 从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然 ...
- 【BZOJ1475】方格取数 [最小割]
方格取数 Time Limit: 5 Sec Memory Limit: 64 MB[Submit][Status][Discuss] Description 在一个n*n的方格里,每个格子里都有一 ...
- 一张图介绍 html中offset、client、scroll、offset 、padding、margin 各种属性介绍
- python3 json、logging、sys模块
json模块 import json dic = {'name':'egon','age':32} # ------------------------------>序列化 f = open(' ...
- Bash Shell 下打开一个TCP / UDP SOCKET
Bash Shell 下打开一个TCP / UDP SOCKET http://jingyan.baidu.com/article/636f38bb6166c3d6b84610d1.html
- Python标准库——collections模块的Counter类
1.collections模块 collections模块自Python 2.4版本开始被引入,包含了dict.set.list.tuple以外的一些特殊的容器类型,分别是: OrderedDict类 ...
- C# 获取存在DataTable1不存在DataTable2的数据的快速方法
通过合并和获得改变两个方法获得差异的部分: dataTable1.AcceptChanges();dataTable1.Merge(dataTable2);DataTable changesTable ...
- mvn常用的构建命令
mvn -v 查看maven版本 mvn compile 编译 mvn test 测试 mvn package 打包 mvn clean 删除target mvn install 安装jar包到本地仓 ...