ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

5.3 下饭考试2

2021-05-05 19:04:07  阅读:138  来源: 互联网

标签:5.3 超级 路径 子树中 下饭 一条 long 节点 考试


5.3考试下饭合集###

T3 超级树

image
image

因为在T1的tarjan伪算法和T2的伪二分上浪费了太多时间(蒟蒻下饭不需要理由),T3看到后没怎么想,上手就推公式。结果推了二十来分钟,根本推不出来,情况过于复杂了,于是就放弃,打了两个表。就这最后还是忘了提交代码,我真行(鼓掌)

正解用的是计数dp(又是没学过的牛马......)
听起来非常玄学,但仔细一想,我滴妈,还真是这么回事!
嗯反正下次出计数dp肯定还不会......

1.状态:

f[i][j],代表i级超级树有j条不同有向路径的情况总数(注意f维护的是情况总数,总数!)答案即为f[n][1];

2.转移:

对于一棵i级超级树,它的所有状态一定是由它下面的两棵(i-1)级超级树推过来的。有四种情况:
(1)从左右子树中分别选出j、k条路径:f[i][j+k] += f[i-1][j] * f[i-1][k];(因为f维护的是情况总数,所以左右子树的f值应该相乘)
(2)从左右子树中分别选出j、k条路径,并将当前的父亲节点也算作一条路径(因为题意说明只有一个节点的路径也算路径):f[i][j+k+1] += f[i-1][j] * f[i-1][k];
(3)从左右子树中分别选出j、k条路径,并在其中挑一条与父亲节点相连: f[i][j+k] += 2 * (j + k) * f[i-1][j] * f[i-1][k];(跳出来的j+k条路径中,每一条都可以作为和父亲节点相连的那条,所以要**(j+k);本dp中记录的是有向路径的情况,那么(j+k)中任意一条路径既可以从父亲节点连到该路径的初始节点,也可以从该路径的末节点连到父亲节点,所以要2)
(4)从左右子树中分别选出j、k条路径,并从中任选两条都与父亲节点连接起来,构成一条新的路径:f[i][j+k-1] = 2 * C(j+k,2) * f[i-1][j] * f[i-1][k];(C那个玩意儿就是组合数学从j+k中取两个的总情况数;还是因为路径有向,抽出的两条路径都和父亲连起来有两种连接方式,从一条路径的起始节点到另一条路径的末节点,或者从另一条路径的起始节点到这条路径的末节点,所以要*2);

3.边界:

f[1][0] = f[i][1] = 1,就是1级超级树要么只有一条路径要么没有路径,且这两种都只有一种情况;

4.时间复杂度:

我们观察一下答案和转移方程:我们要求的是f[n][1],但是转移方程让第二维数字变小的只有情况(4)f[i][j+k-1],且每次最多只能减少1。也就是说对于在n级超级树的状态而言,只有f[n-1][2]能对f[n][1]造成贡献;而又只有f[n-2][3]能对f[n-2][2]造成贡献。以此递推下去,i级超级树能对n级超级树造成贡献的状态也就是到f[i][n-i+2],所以j+k只要从0到n-i+2枚举就可了
另外,本题需要卡常:我们再转移的时候必须不停地取模,但取模和乘法的常数都不小,所以规规矩矩写会T。具体可优化的,比如说通过观察可以发现,四个转移方程都要用到f[i-1][j]*f[i-1][k],所以可以预先把这个数算出来;以及枚举的最大值n-i+2,也可以预先算出来

代码:

#define inf 0x3f3f3f3f
#define ll long long
#define rl register long long
using namespace std;

const int Maxn = 305;

ll n, mod;
ll f[Maxn][Maxn];

int main(){
	scanf("%lld %lld", &n, &mod);
	f[1][0] = f[1][1] = 1;
	for(rl i = 1; i <= n; i++){
		for(rl fab = 0; fab <= n; fab++) f[i-1][fab] %= mod;
		ll jud = n - i + 2;
		for(rl j = 0; j <= jud; j++){
			for(rl k = 0; j + k <= jud; k++){
				rl jud = f[i-1][j] * f[i-1][k] % mod;
				f[i][j+k] += jud;               // 情况(1) 
				f[i][j+k+1] += jud;             // 情况(2)
				f[i][j+k] += (ll)2 * (j + k) * jud;    //情况(3)
				f[i][j+k-1] += (j + k) * (j + k - 1) % mod * jud;  // 情况(4)
			}
		}
	}
	printf("%lld", f[n][1] % mod);
	return 0;
} ```

标签:5.3,超级,路径,子树中,下饭,一条,long,节点,考试
来源: https://www.cnblogs.com/mtr20050125/p/14732391.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有