【AGC005F】Many Easy Problems
Description
题目链接
对于每个\(k\),统计任选\(k\)个点作为关键点的“最小生成树”的大小之和
Solution
正向想法是枚举或者计算大小为\(x\)、叶子数目为\(y\)的子树有多少种,然后贡献答案。这种方法参数多、难统计,可以感受到无法适应\(1e5\)的数据,舍弃
正难则反,自顶向下正向统计难,就考虑自底向上贡献统计。那么这里的自底向上,就应该是对于每一个点,统计其贡献到每个\(ans\)的次数,并累加。
既然要输出k=1...m的答案,可以猜到贡献是一个卷积加速的形式
所以先考虑每个点对某一个k的答案的贡献
任选k个点之后,一个点对答案有1的贡献,当且仅当选择的点不全在以其为根时的某棵子树中
这个很好统计,不全在某棵子树中这个条件很难考虑,不如直接用总数减去不合法的方案,毕竟所有元素用一个组合数就可以搞定\({n \choose k}-\sum_v {size_v\choose k}\)
则
\]
前一部分可以直接算,但后一部分看起来不是一个数组的卷积
遇到这种情况,我们可以用权值作为下标先做一个统计数组\(a[size_v]++\),因为统计时使用的数据与这个\(size_v\)具体是哪一个点的子树大小关系不大,而只和子树大小这个数值有关。因此不以每个点作为视角考虑(具体是谁不重要),而以整棵树为视角考虑,那么\(ans_k\)就会变成
\]
减法卷积算出每个\(ans_k\)的负部分即可
Code
#include <cstdio>
using namespace std;
namespace IO{
const int S=10000000;
char buf[S];
int pos;
void load(){
fread(buf,1,S,stdin);
pos=0;
}
char getChar(){
return buf[pos++];
}
int getInt(){
int x=0,f=1;
char c=getChar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getChar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getChar();}
return x*f;
}
}
using IO::getInt;
const int N=200005;
const int MOD=924844033,G=5;
int n;
int h[N],tot;
struct Edge{
int v,next;
}e[N*2];
int size[N],sum[N];
int fact[N],iact[N];
inline void swap(int &x,int &y){
x^=y^=x^=y;
}
void addEdge(int u,int v){
e[++tot]=(Edge){v,h[u]}; h[u]=tot;
e[++tot]=(Edge){u,h[v]}; h[v]=tot;
}
void readData(){
n=getInt();
int u,v;
for(int i=1;i<n;i++){
u=getInt(); v=getInt();
addEdge(u,v);
}
}
void dfs(int u,int fa){
size[u]=1;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa){
dfs(v,u);
size[u]+=size[v];
sum[size[v]]++;
}
sum[n-size[u]]++;
}
int fmi(int x,int y){
int res=1;
for(;y;x=1ll*x*x%MOD,y>>=1)
if(y&1)
res=1ll*res*x%MOD;
return res;
}
void init(){
fact[0]=1;
for(int i=1;i<=n;i++)
fact[i]=1ll*fact[i-1]*i%MOD;
iact[0]=iact[1]=1;
if(n>1){
iact[n]=fmi(fact[n],MOD-2);
for(int i=n-1;i>=2;i--)
iact[i]=1ll*iact[i+1]*(i+1)%MOD;
}
}
inline int C(int n,int m){
return m>n?0:1ll*fact[n]*iact[m]%MOD*iact[n-m]%MOD;
}
namespace NTT{/*{{{*/
const int S=N*4,B=19;
int n,invn,bit;
int rev[S],W[S][2];
void build(){
int iG=fmi(G,MOD-2);
for(int i=0;i<=B;i++){
W[1<<i][0]=fmi(G,(MOD-1)/(1<<i));
W[1<<i][1]=fmi(iG,(MOD-1)/(1<<i));
}
}
void init(int _n){
for(n=1,bit=0;n<_n;n<<=1,bit++);
invn=fmi(n,MOD-2);
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void ntt(int *a,int f){
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
int w_n,w,u,v;
for(int i=2;i<=n;i<<=1){
w_n=W[i][f];
for(int j=0;j<n;j+=i){
w=1;
for(int k=0;k<(i>>1);k++){
u=a[j+k];
v=1ll*w*a[j+(i>>1)+k]%MOD;
a[j+k]=(u+v)%MOD;
a[j+(i>>1)+k]=(u-v)%MOD;
w=1ll*w*w_n%MOD;
}
}
}
if(f)
for(int i=0;i<n;i++) a[i]=1ll*a[i]*invn%MOD;
}
}/*}}}*/
void solve(){
static int a[NTT::S],b[NTT::S];
for(int i=0;i<n;i++){
a[i]=1ll*sum[i]*fact[i]%MOD;
b[i]=iact[n-1-i];
}
NTT::init(n+n-1);
NTT::ntt(a,0);
NTT::ntt(b,0);
for(int i=0;i<NTT::n;i++) a[i]=1ll*a[i]*b[i]%MOD;
NTT::ntt(a,1);
// now a[n],a[n+1],... represent k=1,2,3,...
int ans;
for(int k=1;k<=n;k++){
ans=(1ll*n*C(n,k)%MOD-1ll*iact[k]*a[n-1+k]%MOD)%MOD;
printf("%d\n",ans<0?ans+MOD:ans);
}
}
int main(){
IO::load();
NTT::build();
readData();
dfs(1,0);
init();
solve();
return 0;
}
【AGC005F】Many Easy Problems的更多相关文章
- 【AGC005F】Many Easy Problems (NTT)
Description 给你一棵\(~n~\)个点的树和一个整数\(~k~\).设为\(~S~\)为树上某些点的集合,定义\(~f(S)~\)为最小的包含\(~S~\)的联通子图的大小.\(~n~ ...
- 【AGC005F】Many Easy Problems FFT 容斥原理
题目大意 给你一棵树,有\(n\)个点.还给你了一个整数\(k\). 设\(S\)为树上某些点的集合,定义\(f(S)\)为最小的包含\(S\)的联通子图的大小. \(n\)个点选\(k\)个点一共有 ...
- 【BZOJ3450】Tyvj1952 Easy 期望DP
[BZOJ3450]Tyvj1952 Easy Description 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是 ...
- 【HDU4565】So Easy!
[HDU4565]So Easy! 题面 要你求 \[ \lceil (a+\sqrt b)^n \rceil \% m \] 其中\(0<a,m<2^{15},(a-1)^2<b& ...
- 【Hello 2018 D】Too Easy Problems
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 可以考虑把所有的题目按照ai排序. 然后顺序考虑最后做出来的题目个数和第i道题目的ai一样. 则1..i-1这些题目就没有用了. 值 ...
- 【AGC005F】简单的问题 Many Easy Problems
Description 链接 Solution 对于每个\(k\),统计任选\(k\)个点作为关键点的"最小生成树"的大小之和 正向想法是枚举或者计算大小为\(x\).叶子数目为\ ...
- 【AGC 005F】Many Easy Problems
Description One day, Takahashi was given the following problem from Aoki: You are given a tree with ...
- 【AGC005 F】Many Easy Problems
神他吗一天考一道码农题两道 FFT(其实还是我推式子一窍不通) 题意 给你一棵 \(n\) 个点的树,再给你一个常数 \(k\). 设 \(S\) 为树上某些点的集合,定义 \(f(S)\) 为最小的 ...
- 【bzoj3450】Tyvj1952 Easy
题目描述 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a个comb就有 ...
随机推荐
- Jquery UI 中的datepicker() ,获取日期后的回调函数onClose()
<head> //引入相关的css/js <link rel="stylesheet" href="//code.jquery.com/ui/1.10. ...
- 任务(task)
任务概述 线程(Thread)是创建并发的底层工具,因此有一定的局限性(不易得到返回值(必须通过创建共享域):异常的捕获和处理也麻烦:同时线程执行完毕后无法再次开启该线程),这些局限性会降低性能同时影 ...
- vue开发小结(上)
前言: 18年年底,就一个字,忙,貌似一到年底哪个公司都在冲业绩,包括我们自己开发自己公司的项目也一样得加把劲.自从18年年初立了个flag17年年终总结——走过2017,迎来2018Flag到现在又 ...
- Quartz.Net分布式任务管理平台(第二版)
前言:在Quartz.Net项目发布第一版后,有挺多园友去下载使用,我们通过QQ去探讨,其中项目中还是存在一定的不完善.所以有了现在这个版本.这个版本的编写完成其实有段时间了一直没有放上去.现在已经同 ...
- Docker容器学习梳理 - 容器硬盘热扩容
前面已介绍了docker很多知识点的操作记录,今天这里梳理下docker容器空间扩展的操作.默认情况下,物理机下创建的docker容器的空间是10G(虚拟机下创建的docker容器空间就是虚拟机的空间 ...
- Notes of Daily Scrum Meeting(12.24)
平安夜了,我们还在这里辛苦地赶代码,整个人都不好了... 今天的团队任务总结如下: 团队成员 今日团队工作 陈少杰 寻找大神帮助,调试网络连接 王迪 建立搜索的UI界面,把算法加入进去 金鑫 调试网络 ...
- vs2013——单元测试&& 性能图
一.如何创建单元测试 下面这个博客中写的很详细: http://***/Article/11186 其中需要注意的是,首先新建工程项目,在此目录下Add单元测试项目,还需要在单元测试项目中引用被测试的 ...
- 必应词典案例分析——个人博客作业week3
案例分析 ——必应词典客户端 软件缺陷常常又被叫做Bug,即为计算机软件或程序中存在的某种破坏正常运行能力的问题.错误,或者隐藏的功能缺陷. 缺陷的存在会导致软件产品在某种程度上不能满足用户的需要.I ...
- 《Linux内核设计与实现》 第八周读书笔记 第四章 进程调度
20135307 张嘉琪 第八周读书笔记 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有 ...
- opencv学习笔记(三)
imread()读入图,第一个参数,const string&类型的filename,填我们需要载入的图片路径名, 第二个参数,int类型的flags,为载入标识,它指定一个加载图像的颜色类型 ...