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 ...
随机推荐
- pmap用法小计
By francis_hao Aug 4,2017 pmap-报告进程的内存映射. 概要 pmap [options] pid [...] 描述 pmap命令用来报告一个或多个进程的 ...
- Codeforces Round #534 (Div. 2) D. Game with modulo(取余性质+二分)
D. Game with modulo 题目链接:https://codeforces.com/contest/1104/problem/D 题意: 这题是一个交互题,首先一开始会有一个数a,你最终的 ...
- js中Date()对象详解
var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-???? ...
- ViewPager使用--文章集锦
viewpager中彻底性动态添加.删除Fragment Android ViewPager使用详解 fragment中嵌套viewpager,vierpager中有多个fragment,不显示 .. ...
- Java并发(6)- CountDownLatch、Semaphore与AQS
引言 上一篇文章中详细分析了基于AQS的ReentrantLock原理,ReentrantLock通过AQS中的state变量0和1之间的转换代表了独占锁.那么可以思考一下,当state变量大于1时代 ...
- 图论:KM算法
如果,将求二分图的最大匹配的所有匹配边的权重看做1 那么用匈牙利算法求二分图的最大匹配的问题也可以看成求二分图的最大权匹配 如果边权是特例,我们就要使用KM算法来做了 这个算法其实还是比较难的,会用就 ...
- OOP第三次上机
上机问题 T1 CSet 还是熟悉的CSet,只是多了个构造函数以及收缩空间. T2 SingleTon 单例问题. 用一个指针保存唯一的实例,用户无法在外部直接新建实例,只能使用外部接口(函数),函 ...
- MongoDB安装成为Windows服务
使用以下命令将MongoDB安装成为Windows服务.笔者的MongoDB目录为C:\Program Files\MongoDB\Server\3.6\bin 切换到C:\Program Files ...
- kthread_create与kernel_thread的区别【栈】
转自:http://blog.chinaunix.net/uid-25513153-id-2888903.html kthread_create与kernel_thread的区别 kernel thr ...
- linux coredump测试
1 )如何生成 coredump 文件 ? 登陆 LINUX 服务器,任意位置键入 echo "ulimit -c 1024" >> /etc/profile 退出 L ...