2020牛客暑期多校训练营Valuable Forests(动态规划,组合数学,prufer序列)

本文主要是介绍2020牛客暑期多校训练营Valuable Forests(动态规划,组合数学,prufer序列),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Valuable Forests

题目描述

在这里插入图片描述

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例1

输入

5 1000000007
2
3
4
5
107

输出

2
24
264
3240
736935633

题目大意

给定 n n n个节点,求这些节点组成的森林的所有可能中每个点的度的平方和。
要求答案 m o d mod mod给定的模数 M M M

分析

分析这题,发现难点在于,有很多很多的可能,比如说森林中树的个数、每棵树的节点分布情况、树的大小……那么,这些里面最重要的就是前两条,我们分别用数组存下。

d p [ i ] dp[i] dp[i]表示在森林中有 i i i个节点时的总方案数。
f [ i ] f[i] f[i]表示大小为 i i i的无根树的答案。

那么一看我定义的变量就知道是个 d p dp dp题。因为每次考虑最后一棵树就可以完成转移了。

  • 我们先考虑 d p [ i ] dp[i] dp[i]的转移。
    那么假如剩下 j j j个节点给最后一棵树,那么之前的方案是 d p [ i − j ] dp[i-j] dp[ij],然后对于每个方案, j j j个节点的可能是 j j − 2 j^{j-2} jj2,然后考虑节点的编号,由于没有说一定是顺序的,所以前 i i i个节点编号不一定是 1 ∼ i 1\sim i 1i,所以要乘上其组合数,运用隔板法,又因为第 i i i号节点一定要在最后一棵树,否则会重复,所以点数选择要减一,即 C i − 1 j − 1 C_{i-1}^{j-1} Ci1j1
    所以,枚举 j j j即可,如下:
    d p [ i ] = ∑ j = 1 i d p [ i − j ] ∗ j j − 2 ∗ C i − 1 j − 1 dp[i]=\mathop{\sum}\limits_{j=1}^idp[i-j]*j^{j-2}*C_{i-1}^{j-1} dp[i]=j=1idp[ij]jj2Ci1j1
  • 我们再考虑 f [ i ] f[i] f[i]的转移。
    这里要用到一个 p r u f e r prufer prufer序列,说的是一个无根树和一个序列是一一对应的。首先枚举每个节点 p p p,然后再枚举每个节点的度 j j j(度不会大于点数-1),那么答案中肯定是乘上一个 j 2 j^2 j2,然后考虑节点的编号,同上要乘上一个 C i − 2 j − 1 C_{i-2}^{j-1} Ci2j1,减二是因为在构造 p r u f e r prufer prufer的时候是剩下一条边,以防止有自环出现。然后是节点的顺序,乘上一个 ( i − 1 ) i − 1 − j (i-1)^{i-1-j} (i1)i1j
    所以枚举 p , j p,j p,j即可,如下:
    f [ i ] = ∑ p = 1 i ∑ j = 1 i − 1 j 2 ∗ C i − 2 j − 1 ∗ ( i − 1 ) i − 1 − j f[i]=\mathop{\sum}\limits_{p=1}^{i}\mathop{\sum}\limits_{j=1}^{i-1}j^2*C_{i-2}^{j-1}*(i-1)^{i-1-j} f[i]=p=1ij=1i1j2Ci2j1(i1)i1j
    然后发现 p p p在转移的时候并没有用,所以可以把那个 ∑ \sum 压掉。如下:
    f [ i ] = i ∗ ∑ j = 1 i − 1 j 2 ∗ C i − 2 j − 1 ∗ ( i − 1 ) i − 1 − j f[i]=i*\mathop{\sum}\limits_{j=1}^{i-1}j^2*C_{i-2}^{j-1}*(i-1)^{i-1-j} f[i]=ij=1i1j2Ci2j1(i1)i1j

然后就是把上面求出来的一起来算答案。设 a n s [ i ] ans[i] ans[i]表示有 i i i个节点的时候题目的答案。

  • 我们考虑 a n s [ i ] ans[i] ans[i]的转移
    首先枚举一个 j j j表示最后的一棵树有 j j j个节点,然后递推。那么显然前面的答案是 a n s [ i − j ] ∗ j j − 2 ans[i-j]*j^{j-2} ans[ij]jj2。然后是当前的答案是 d p [ j − i ] ∗ f [ j ] dp[j-i]*f[j] dp[ji]f[j]表示当前算出来的答案,然后加起来。最后一样的,要考虑节点编号的问题,乘上节点的组合数。
    所以枚举 j j j,可以得到:
    a n s [ i ] = ∑ j = 1 i C i − 1 j − 1 ∗ ( j j − 2 ∗ a n s [ i − j ] + f [ j ] ∗ d p [ i − j ] ) ans[i]=\mathop{\sum}\limits_{j=1}^{i}C_{i-1}^{j-1}*(j^{j-2}*ans[i-j]+f[j]*dp[i-j]) ans[i]=j=1iCi1j1(jj2ans[ij]+f[j]dp[ij])

做的时候先打表,然后直接输出即可,见代码,注意模。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=5010;
ll mod,C[MAXN][MAXN],dp[MAXN],f[MAXN],ans[MAXN],qp[MAXN][MAXN];//long long
ll ksm(ll a,ll p){if(p<0) return 1ll;else return qp[a][p];}//指数为负是1
int main()
{int T,nnn;scanf("%d%lld",&T,&mod);C[0][0]=1;for(int i=1;i<=5000;i++){C[i][0]=1;for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;}//用杨辉三角处理组合数for(int i=0;i<=5000;i++){qp[i][0]=1;for(int j=1;j<=5000;j++)qp[i][j]=qp[i][j-1]*i%mod;}//预处理快速幂,让你的快速幂成为O(1)dp[0]=1;for(int i=1;i<=5000;i++)for(int j=1;j<=i;j++)dp[i]=(dp[i]+dp[i-j]*ksm(j,j-2)%mod*C[i-1][j-1]%mod)%mod;//预处理dpfor(int i=1;i<=5000;i++){for(int j=1;j<i;j++)f[i]=(f[i]+j*j%mod*C[i-2][j-1]%mod*ksm(i-1,i-1-j)%mod)%mod;f[i]=f[i]*i%mod;}//预处理ffor(int i=1;i<=5000;i++)for(int j=1;j<=i;j++)ans[i]=(ans[i]+C[i-1][j-1]*(ksm(j,j-2)*ans[i-j]%mod+f[j]*dp[i-j]%mod)%mod)%mod;//算答案while(T--){scanf("%d",&nnn);printf("%lld\n",ans[nnn]);}//直接输出
}

END

要素 bug颇多……

这篇关于2020牛客暑期多校训练营Valuable Forests(动态规划,组合数学,prufer序列)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/233034

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

uva 10014 Simple calculations(数学推导)

直接按照题意来推导最后的结果就行了。 开始的时候只做到了第一个推导,第二次没有继续下去。 代码: #include<stdio.h>int main(){int T, n, i;double a, aa, sum, temp, ans;scanf("%d", &T);while(T--){scanf("%d", &n);scanf("%lf", &first);scanf

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

uva 11044 Searching for Nessy(小学数学)

题意是给出一个n*m的格子,求出里面有多少个不重合的九宫格。 (rows / 3) * (columns / 3) K.o 代码: #include <stdio.h>int main(){int ncase;scanf("%d", &ncase);while (ncase--){int rows, columns;scanf("%d%d", &rows, &col

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

uva 10131 最长子序列

题意: 给大象的体重和智商,求体重按从大到小,智商从高到低的最长子序列,并输出路径。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vect