BZOJ 3684 大朋友和多叉树
BZOJ 3684 大朋友和多叉树
Description
我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为1的结点是叶子结点;对于任一点权大于1的结点u,u的孩子数目deg[u]属于集合D,且u的点权等于这些孩子结点的点权之和。
给出一个整数s,你能求出根节点权值为s的神犇多叉树的个数吗?请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。
我们只需要知道答案关于\(950009857\)(\(453*2^{21}+1\),一个质数)取模后的值。
Input
第一行有\(2\)个整数\(s,m\)。
第二行有\(m\)个互异的整数,\(d[1],d[2],…,d[m]\),为集合\(D\)中的元素。
Output
输出一行仅一个整数,表示答案模\(950009857\)的值。
Sample Input
4 2
2 3
Sample Output
10
前置知识:
\(\text{Lagrange}\)反演(金策的论文中有讲):
若两个没有常数项的函数\(f(x)\)和\(g(x)\)满足:
\]
(也称这两个函数互为复合逆。)
我们就有:
\]
设\(T(x)\)为答案的生成函数。
我们有:
\]
加上一个\(x\)是因为要考虑\(x\)为叶子的情况。
移项:
\]
设:
\]
则:
\Rightarrow [x^n]T(x)=\frac{1}{n}[w^{n-1}](\frac{w}{f(w)})^n
\]
\(\frac{w}{f(w)}\)上下约掉\(w\)后发现相当于将\(f(w)\)的每一项向左平移再求逆。
然后:
\]
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 100005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
const ll mod=950009857;
ll ksm(ll t,ll x) {
ll ans=1;
for(;x;x>>=1,t=t*t%mod)
if(x&1) ans=ans*t%mod;
return ans;
}
ll NTT(ll *a,int d,int flag) {
static int rev[N<<2];
static int G=7;
int n=1<<d;
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int s=1;s<=d;s++) {
int len=1<<s,mid=len>>1;
ll w=flag==1?ksm(G,(mod-1)/len):ksm(G,mod-1-(mod-1)/len);
for(int i=0;i<n;i+=len) {
ll t=1;
for(int j=0;j<mid;j++,t=t*w%mod) {
ll u=a[i+j],v=a[i+j+mid]*t%mod;
a[i+j]=(u+v)%mod;
a[i+j+mid]=(u-v+mod)%mod;
}
}
}
if(flag==-1) {
ll inv=ksm(n,mod-2);
for(int i=0;i<n;i++) a[i]=a[i]*inv%mod;
}
}
void Inv(ll *inv,ll *a,int d) {
static ll A[N<<2];
if(!d) {
inv[0]=ksm(a[0],mod-2);
return ;
}
Inv(inv,a,d-1);
for(int i=0;i<1<<d;i++) A[i]=a[i];
for(int i=1<<d;i<1<<d+1;i++) A[i]=inv[i]=0;
NTT(A,d+1,1),NTT(inv,d+1,1);
for(int i=0;i<1<<d+1;i++) inv[i]=(2*inv[i]-inv[i]*inv[i]%mod*A[i]%mod+mod)%mod;
NTT(inv,d+1,-1);
for(int i=1<<d;i<1<<d+1;i++) inv[i]=0;
}
void Der(ll *ans,ll *a,int d) {
int n=1<<d;
for(int i=0;i<n-1;i++) ans[i]=a[i+1]*(i+1)%mod;
ans[n-1]=0;
}
void Int(ll *ans,ll *a,int d) {
int n=1<<d;
for(int i=n-1;i;i--) ans[i]=a[i-1]*ksm(i,mod-2)%mod;
ans[0]=0;
}
void Ln(ll *ln,ll *a,int d) {
static ll inv[N<<2],der[N<<2];
for(int i=0;i<1<<d+1;i++) inv[i]=der[i]=0;
Inv(inv,a,d);Der(der,a,d);
NTT(inv,d+1,1),NTT(der,d+1,1);
for(int i=0;i<1<<d+1;i++) ln[i]=inv[i]*der[i]%mod;
NTT(ln,d+1,-1);
Int(ln,ln,d);
for(int i=1<<d;i<1<<d+1;i++) ln[i]=0;
}
void Exp(ll *ex,ll *a,int d) {
static ll A[N<<2],ln[N<<2];
if(d==0) {
ex[0]=1;
return ;
}
Exp(ex,a,d-1);
for(int i=0;i<1<<d+1;i++) A[i]=ln[i]=0;
for(int i=0;i<1<<d;i++) A[i]=a[i];
Ln(ln,ex,d);
NTT(ln,d+1,1),NTT(A,d+1,1);
NTT(ex,d+1,1);
for(int i=0;i<1<<d+1;i++) ex[i]=ex[i]*(1-ln[i]+A[i]+mod)%mod;
NTT(ex,d+1,-1);
for(int i=1<<d;i<1<<d+1;i++) ex[i]=0;
}
ll A[N<<2],inv[N<<2],ln[N<<2],ex[N<<2];
ll f[N<<2];
int n,m;
int main() {
n=Get(),m=Get();
int d=ceil(log2(n+1));
for(int i=1;i<=m;i++) {
int a=Get();
f[a-1]=mod-1;
}
f[0]=1;
Inv(inv,f,d);
Ln(ln,inv,d);
for(int i=0;i<1<<d;i++) ln[i]=ln[i]*n%mod;
Exp(ex,ln,d);
cout<<ex[n-1]*ksm(n,mod-2)%mod;
return 0;
}
BZOJ 3684 大朋友和多叉树的更多相关文章
- BZOJ 3684: 大朋友和多叉树 [拉格朗日反演 多项式k次幂 生成函数]
3684: 大朋友和多叉树 题意: 求有n个叶子结点,非叶节点的孩子数量\(\in S, a \notin S\)的有根树个数,无标号,孩子有序. 鏼鏼鏼! 树的OGF:\(T(x) = \sum_{ ...
- [BZOJ3684][拉格朗日反演+多项式求幂]大朋友和多叉树
题面 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为\(1\)的结点是叶子结 ...
- 【BZOJ3684】大朋友和多叉树(拉格朗日反演)
题目链接 题意 求满足如下条件的多叉树个数: 1.每一个点的儿子个数在给定的集合 \(S\) 内 2.总的叶子节点树为 \(s\) 儿子之间有顺序关系,但节点是没有标号的. Sol 拉格朗日反演板子题 ...
- [BZOJ3684]大朋友和多叉树
设答案为$f_s$,它的生成函数为$\begin{align*}F(x)=\sum\limits_{i=0}^\infty f_ix^i\end{align*}$,则我们有$\begin{align* ...
- BZOJ3684 大朋友和多叉树(多项式相关计算)
设$f(x)$为树的生成函数,即$x^i$的系数为根节点权值为$i$的树的个数.不难得出$f(x)=\sum_{k\in D}f(x)^k+x$我们要求这个多项式的第$n$项,由拉格朗日反演可得$[x ...
- 【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演
这题一看就觉得是生成函数的题... 我们不妨去推下此题的生成函数,设生成函数为$F(x)$,则$[x^s]F(x)$即为答案. 根据题意,我们得到 $F(x)=x+\sum_{i∈D} F^i(x)$ ...
- bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)
题面 传送门 题解 首先你得知道什么是拉格朗日反演->这里 我们列出树的个数的生成函数 \[T(x)=x+\prod_{i\in D}T^i(x)\] \[T(x)-\prod_{i\in D} ...
- [BZOJ 3652]大新闻
[BZOJ 3652] 大新闻 题意 随机从 \([0,n)\) 中选取一个整数 \(x\), 并从 \([0,n)\) 中再选取一个整数 \(y\). 有 \(p\) 的概率选取一个能令 \(x\o ...
- P2008 大朋友的数字
题目描述 有一批大朋友(年龄15岁以上),他们每人手上拿着一个数字,当然这个数字只有1位,也就是0到9之间.每个大朋友的分数为在他之前的最长不下降子序列中所有数之和.(这个序列必须以它作为结尾!)如有 ...
随机推荐
- 知其所以然~mongodb副本集
MongoDB 复制(副本集) MongoDB复制是将数据同步在多个服务器的过程. 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性. 复制还允许您 ...
- Node.js与Sails~redis组件的使用
有段时间没写关于NodeJs的文章了,今天也是为了解决高并发的问题,而想起了这个东西,IIS的站点在并发量达到200时有了一个瓶颈,于是想到了这个对高并发支持比较好的框架,nodeJs在我之前写出一些 ...
- what a fuck!这是什么鬼东西?
Topic Link http://ctf5.shiyanbar.com/DUTCTF/1.html 1) 打开链接发现一片看不懂的东西,还真是WTF? 2)分析发现是Jother编码 将其放到浏览器 ...
- bash shell第一课
自学shell,又被老师说教,上英语课不好好学习英语四级怎么过,哈哈,那也没有数据对我的吸引力大啊,为了爱与梦想!!! 回忆一下文件格式: 文件名的扩展名为 .sh 文件内容开头必为 #!bin/ ...
- 设计模式总结篇系列:享元模式(Flyweight)
我们都知道,Java中的String类具有如下特性:String是一个不可变类,当直通过用字符串方式使用String对象时,Jvm实际上在内存中只存有一份,且存在字符串常量池中.当对字符串直接进行修改 ...
- Golang垃圾回收机制(二)
原文:https://blog.csdn.net/qq_15427331/article/details/54613635 Go语言正在构建的垃圾收集器(GC),似乎并不像宣传中那样的,技术上迎来了巨 ...
- ADO.NET基础学习 二(Command对象)
②command对象用来操作数据库.(三个重要的方法:ExecuteNonQuery(),ExecuteReader(),ExecuteScalar()) ⑴以update(改数据)为例,用到Exec ...
- 【转】Android 之最新最全的Intent传递数据方法
原文地址:https://www.jianshu.com/p/1169dba99261 intent传递数据 为什么要和intent单独拿出来讲,因为Intent传递数据也是非常重要的 一.简单的传递 ...
- 开源负载测试工具k6比JMeter更容易的5件事
k6是GitHub上提供的开源负载测试工具.它是用Go编写的,并运行用JavaScript编写的测试脚本.它受到了开发人员,测试人员和DevOps团队的强烈兴趣,并拥有超过4400名GitHub明星. ...
- 【Webpack 杂谈】帮助文档翻译:Webpack的模块
页面出自Webpack官方文档(撰写时,是v4.1.1) 其实Webpack本身有中文文档,不知道是谁去撰写的,但是自己翻译一遍感觉更好理解. https://webpack.js.org/conce ...