codeforces 955F Cowmpany Cowmpensation 树上DP+多项式插值
给一个树,每个点的权值为正整数,且不能超过自己的父节点,根节点的最高权值不超过D
问一共有多少种分配工资的方式?
题解:
A immediate simple observation is that we can compute the answer in $O(nD) $with a simple dynamic program. How to speed it up though?
To speed it up, we need the following lemma.
Lemma 1: For a tree with nn vertices, the answer is a polynomial in $D$ of degree at most nn.
We can prove this via induction, and the fact that for any polynomial $ p(x) $ of degree dd, the sum $\sum p_i $ is a polynomial in $n$ of degree $d+1$
Now the solution is easy: compute the answerfor $ 0≤D≤n $ and use interpolation to compute the answer for $ D>n $.
The complexity is $O(n^2)$ or the initial dp and $O(n)$ for the interpolation step.
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#pragma GCC optimize("unroll-loops")
#define inline inline __attribute__( \
(always_inline, __gnu_inline__, __artificial__)) \
__attribute__((optimize("Ofast"))) __attribute__((target("sse"))) \
__attribute__((target("sse2"))) __attribute__((target("mmx")))
#define IO ios::sync_with_stdio(false);
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
#define per(ii,a,b) for(int ii=b;ii>=a;--ii)
#define for_node(x,i) for(int i=head[x];i;i=e[i].next)
#define show(x) cout<<#x<<"="<<x<<endl
#define showa(a,b) cout<<#a<<'['<<b<<"]="baidu<a[b]<<endl
#define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl
#define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
using namespace std;
const int maxn=4e3+10,maxm=2e6+10;
const int INF=0x3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
//head
ll casn,n,m,k;
ll num[maxn];
ll pow_mod(ll a,ll b,ll c=mod,ll ans=1){while(b){if(b&1) ans=(a*ans)%c;a=(a*a)%c,b>>=1;}return ans;}
namespace polysum {
const int maxn=101000;
const ll mod=1e9+7;
ll a[maxn],f[maxn],g[maxn],p[maxn],p1[maxn],p2[maxn],b[maxn],h[maxn][2],C[maxn];
ll calcn(int d,ll *a,ll n) {//d´Î¶àÏîʽ(a[0-d])ÇóµÚnÏî
if (n<=d) return a[n];
p1[0]=p2[0]=1;
rep(i,0,d) {
ll t=(n-i+mod)%mod;
p1[i+1]=p1[i]*t%mod;
}
rep(i,0,d) {
ll t=(n-d+i+mod)%mod;
p2[i+1]=p2[i]*t%mod;
}
ll ans=0;
rep(i,0,d) {
ll t=g[i]*g[d-i]%mod*p1[i]%mod*p2[d-i]%mod*a[i]%mod;
if ((d-i)&1) ans=(ans-t+mod)%mod;
else ans=(ans+t)%mod;
}
return ans;
}
void init(int maxm) {//³õʼ»¯Ô¤´¦Àí½×³ËºÍÄæÔª(ȡģ³Ë·¨)
f[0]=f[1]=g[0]=g[1]=1;
rep(i,2,maxm+4) f[i]=f[i-1]*i%mod;
g[maxm+4]=pow_mod(f[maxm+4],mod-2);
per(i,1,maxm+3) g[i]=g[i+1]*(i+1)%mod;
}
}
ll dp[maxn][maxn];
struct node {int to,next;}e[maxm];int head[maxn],nume;
void add(int a,int b){e[++nume]=(node){b,head[a]};head[a]=nume;} void dfs(int now){
rep(i,1,n) dp[now][i]=1;
for(int i=head[now];i;i=e[i].next){
dfs(e[i].to);
rep(j,1,n) dp[now][j]=dp[now][j]*dp[e[i].to][j]%mod;
}
rep(i,1,n) dp[now][i]=(dp[now][i]+dp[now][i-1])%mod;
} int main() {
//#define test
#ifdef test
auto _start = chrono::high_resolution_clock::now();
freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif IO;
cin>>n>>k;
rep(i,2,n){
int a;
cin>>a;
add(a,i);
}
dfs(1);
polysum::init(n+1);
rep(i,0,n+1){
num[i]=dp[1][i];
}
ll ans=polysum::calcn(n,num,k);
cout<<ans<<endl; #ifdef test
auto _end = chrono::high_resolution_clock::now();
cerr << "elapsed time: " << chrono::duration<double, milli>(_end - _start).count() << " ms\n";
fclose(stdin);fclose(stdout);system("out.txt");
#endif
return 0;
}
codeforces 955F Cowmpany Cowmpensation 树上DP+多项式插值的更多相关文章
- [CF995F]Cowmpany Cowmpensation[树形dp+拉格朗日插值]
题意 给你一棵树,你要用不超过 \(D\) 的权值给每个节点赋值,保证一个点的权值不小于其子节点,问有多少种合法的方案. \(n\leq 3000, D\leq 10^9\) 分析 如果 \(D\) ...
- Codeforces 995F Cowmpany Cowmpensation - 组合数学
题目传送门 传送点I 传送点II 传送点III 题目大意 给定一个棵$n$个点的有根树和整数$D$,给这$n$个点标号,要求每个节点的标号是正整数,且不超过父节点的标号,根节点的标号不得超过D. 很容 ...
- 整数拆分 [dp+多项式插值]
题意 $1 \leq n \leq 10^{18}$ $2 \leq m \leq 10^{18}$ $1 \leq k \leq 20$ 思路 n,m较小 首先考虑朴素的$k=1$问题: $f[i] ...
- Codeforces F. Cowmpany Cowmpensation
Description 有一棵树,现在要给每个节点赋一个在1到D之间的权值,问有多少种方案满足任意一个节点的权值都不大于其父亲的权值. n<=3000,D<=1e9 题面 Solution ...
- 【CF995F】Cowmpany Cowmpensation(动态规划,拉格朗日插值)
[CF995F]Cowmpany Cowmpensation(多项式插值) 题面 洛谷 CF 题解 我们假装结果是一个关于\(D\)的\(n\)次多项式, 那么,先\(dp\)暴力求解颜色数为\(0. ...
- [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)
[BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆) 题面 一棵二叉树的所有点的点权都是给定的集合中的一个数. 让你求出1到m中所有权 ...
- CodeForces 690C2 Brain Network (medium)(树上DP)
题意:给定一棵树中,让你计算它的直径,也就是两点间的最大距离. 析:就是一个树上DP,用两次BFS或都一次DFS就可以搞定.但两次的时间是一样的. 代码如下: #include<bits/std ...
- Codeforces Round #526 (Div. 2) D. The Fair Nut and the Best Path 树上dp
D. The Fair Nut and the Best Path 题意:给出一张图 点有权值 边也要权值 从任意点出发到任意点结束 到每个点的时候都可以获得每个点的权值,而从边走的时候都要消耗改边的 ...
- 【CF995F】 Cowmpany Cowmpensation
CF995F Cowmpany Cowmpensation Solution 这道题目可以看出我的代码能力是有多渣(代码能力严重退化) 我们先考虑dp,很容易写出方程: 设\(f_{i,j}\)表示以 ...
随机推荐
- HDU 1035(走迷宫 模拟)
题意是给定初始位置在一个迷宫中按照要求前进,判断多少步能离开迷宫或者多少步会走入一个长达多少步的循环. 按要求模拟前进的位置,对每一步在 vis[ ] 数组中进行已走步数的记录,走出去或走到已走过的位 ...
- Nginx 学习笔记(九)申请Let's Encrypt通配符HTTPS证书
Let's Encrypt 宣布 ACME v2 正式支持通配符证书,并将继续清除 Web 上采用 HTTPS 的障碍,让每个网站轻松获取管理证书.消息一出,马上就有热心用户分享出了 Let's En ...
- java项目中文件含义
1. java项目 .project:是工程构建配置文件 .classpath:保存的是项目所用的外部引用包的路径 .settings:记录项目配置变化的记录文件夹 src:sourcefolder项 ...
- Spark源码剖析 - SparkContext的初始化(三)_创建并初始化Spark UI
3. 创建并初始化Spark UI 任何系统都需要提供监控功能,用浏览器能访问具有样式及布局并提供丰富监控数据的页面无疑是一种简单.高效的方式.SparkUI就是这样的服务. 在大型分布式系统中,采用 ...
- redis基本操作
''' pip install redis redis 可以看成内存中的大字典 redis五大数据类型 --> 指的是第一层的value值的类型 - 字符串 "k1" - 列 ...
- 开源ETL工具之Kettle介绍
What 起源 Kettle是一个Java编写的ETL工具,主作者是Matt Casters,2003年就开始了这个项目,最新稳定版为7.1. 2005年12月,Kettle从2.1版本开始进入了开源 ...
- 细说REST API
1. REST概述 REST(英文:Representational State Transfer,又称具象状态传输)是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一 ...
- 二、linux IO 编程---系统调用和POSIX标准和标准IO
2.1 系统调用 2.1.1 概念 所谓系统调用(system call)是指曹错系统提供给用户程序的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的特殊服务. 应用程序可以 ...
- Mac OSX常用工具
换Mac有几个月了,刚换的那个月折腾了整整一个月,初用OSX很不适应,这是一种错觉,就好比说了十几年汉语,突然说英语肯定很别扭,适应后就会觉得英语更加实用. Life weiboX(http://we ...
- faster rcnn 做识别
faster rcnn 主要分为四个部分: 1. convolutional part: 特征提取 可以使用vgg,resnet 等等 2.region proposal network: 生成 re ...