Codeforces Round 896 (Div. 1) C. Travel Plan(树形dp+组合数学)

文章讲述了如何使用动态规划解决一个关于完全二叉树的问题,通过记忆化子树路径长度和最大值,计算不同路径长度和最大值组合对总贡献的和,对特定模数取余。
题目

有一棵n(1<=n<=1e18)个点的树,

点i连着2*i和2*i+1两个点,构成一棵完全二叉树

对于每个点i,记其值为a[i],a[i]可以取[1,m](1<=m<=1e5)的整数

记i到j的简单路径上的最大值为s[i][j],

则一棵权值确定的树对答案的贡献是\sum_{i=1}^{n}\sum_{j=i+1}^{n}s[i][j]

现在求所有可能情况下的树的贡献之和,答案对998244353取模

实际t<=200组样例,但保证summ不超过1e5

思路来源

羊村群小羊

题解

大致的思路就是把每个长度的路径都统计算出来,然后再算贡献

而n个点的树总是可以拆成左子树和右子树继续递归下去的,有子结构的概念

所以可以按子树大小做记忆化,每棵子树暴力维护所有长度的路径进行合并

由于路径长度最长2*logn,这里固定开了128长度的vector,只对这些做合并

dp[i][2]表示当前节点u的子树长度为i的路径的条数

其中dp[i][0]表示两端都位于子树内部的路径,dp[i][1]表示有一端位于根节点的路径

求出路径方案数后求贡献,最大值为i的方案数,首先特判i=1,

然后稍作容斥,方案数等于m个值从[1,i]任取减去m个值从[1,i-1]任取

长为i的路径的方案数*剩下n-i个点任取的方案数*最大值为j的方案数*最大值j,

就是当路径长度为i,而最大值为j时,(i,j)对答案的贡献,统计所有贡献累加即可

心得

int k = std::__lg(n + 1);
ll ls=((1LL << (k - 1)) - 1) + std::min(1LL << (k - 1), n - (1LL << k) + 1);
ll rs=n-1-ls;

求左子树大小这里,抄了一下jiangly的代码,但后来想了想也很好理解

对于倒数第二层往上,是左右子树平分的

而对于最后一层,左子树能拿到的大小,为min(剩下的点数,最后一层的一半)

代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef array<int,2> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef unsigned ui;
//typedef __uint128_t L;
typedef unsigned long long L;
typedef unsigned long long ull;
const int N=1e5+10,M=128,mod=998244353;
int t,m,pw[N][M];
ll n;
map<ll,vector<P>>mp;//dp[i][2]表示是否开口的方案数
void add(int &x,int y){
	x=(x+y)%mod;
}
vector<P>dfs(ll n){
	if(n==0)return vector<P>(1,{0,0});
	if(n==1)return vector<P>(1,{0,1});
	if(mp.count(n))return mp[n];
    int k = std::__lg(n + 1);
	ll ls=((1LL << (k - 1)) - 1) + std::min(1LL << (k - 1), n - (1LL << k) + 1);
	ll rs=n-1-ls;
	vector<P>l=dfs(ls),r=dfs(rs);
	int sl=SZ(l),sr=SZ(r);
	//printf("n:%lld lsz:%d rsz:%d\n",n,sl,sr);
	vector<P>dp(128,{0,0});
	rep(i,0,sl-1){
		rep(j,0,sr-1){
			if(!l[i][1] || !r[j][1])continue;
			add(dp[i+j+2][0],1ll*l[i][1]*r[j][1]%mod);
		}
	}
	rep(i,0,sl-1){
		add(dp[i][0],l[i][0]);
		add(dp[i][0],l[i][1]);
		add(dp[i+1][1],l[i][1]);
	}
	rep(i,0,sr-1){
		add(dp[i][0],r[i][0]);
		add(dp[i][0],r[i][1]);
		add(dp[i+1][1],r[i][1]);
	}
	add(dp[0][1],1);
	return mp[n]=dp;
}
int modpow(int x,ll n,int mod){
	if(!n)return 1;
	int res=1;
	for(;n;n>>=1,x=1ll*x*x%mod){
		if(n&1)res=1ll*res*x%mod;
	}
	return res;
}
int cal(int sz,int v){
	if(v==1)return 1;
	return (pw[v][sz]-pw[v-1][sz]+mod)%mod;
}
int sol(){
	vector<P>dp=dfs(n);
	int sz=SZ(dp),res=0;
	rep(j,0,sz-1){
		int cnt=(dp[j][0]+dp[j][1])%mod,len=j+1;
		if(len>n)break;
		int oth=modpow(m,n-len,mod)%mod;
		rep(i,1,m){
			add(res,1ll*cnt*cal(len,i)%mod*i%mod*oth%mod);
		}
	}
	return res;
}
int main(){
	rep(i,1,N-1){
		pw[i][0]=1;
		rep(j,1,M-1){
			pw[i][j]=1ll*pw[i][j-1]*i%mod;
		}
	}
	sci(t);
	while(t--){
		scanf("%lld%d",&n,&m);
		printf("%d\n",sol());
	}
	return 0;
}

【重要提示】本资源设置为0积分下载,若非0积分请勿轻易下载 亲爱的CSDN用户: 首先感谢你点进这个资源页面。我需要提前说明一个重要情况: 本资源原本已设置为“0积分下载”,即作者希望完全免费共享。但CSDN平台有时会根据文件的下载热度、文件大小、用户权限等因素,自动将部分资源的积分调整为非0数值(如1积分、2积分、5积分等)。这是平台系统的自动行为,而非作者本人的设定。 因此,如果你当前看到该资源的下载所需积分不是0(例如显示为1、2、3……),请谨慎决定是否下载。 如果你按照非0积分支付并下载后发现资源内容不符合预期、链接失效,或者实际上该资源本应是免费的,作者无法为此承担积分损失或退还操作。强烈建议:仅在页面显示为0积分时进行下载。 另外,本资源描述中并未直接提供具体的下载地址或外部链接,因为它本身是一个通过CSDN官方上传通道提交的文件/内容包。如果你看到描述中没有外部网盘地址,这是正常的——资源文件应通过CSDN内置的“下载”按钮获取。若因平台积分显示异常导致你支付了积分,请优先联系CSDN客服咨询积分退还政策,作者没有权限修改平台自动设定的积分值。 感谢你的理解与支持。技术分享本应开放,但受限于平台规则,特此提醒如上。祝学习进步!
内容概要:本文系统介绍了基于最小势能原理(即能量法)的物理信息神经网络(PINNs)在求解固体力学二维问题中的理论框架与应用实践,并提供了完整的PyTorch代码实现案例。该方法通过将物理系统的总势能泛函嵌入神经网络的损失函数中,利用深度学习框架直接求解满足控制方程和边界条件的位移场近似解,避免了传统数值方法对网格划分的依赖。文章重点剖析了基于变分原理的能量形式如何替代强形式偏微分方程构建损失项,提升了求解的稳定性与泛化能力。同时,研究对比了不同PINNs架构与训练策略在处理复杂几何形状、非均匀材料属性及非线性力学行为时的精度、收敛性与计算效率,验证了其在处理经典弹性力学问题(如平面应力/应变问题)中的有效性与潜力。配套代码便于读者复现结果并拓展至更广泛的工程应用场景。; 适合人群:具备一定深度学习基础和固体力学知识的研究生、科研人员及工程技术从业者,特别适用于从事计算力学、智能仿真、物理驱动建模、结构分析等方向的研究者。; 使用场景及目标:①掌握基于能量法的PINNs建模范式,理解其相较于传统有限元法的优势与局限;②研究物理信息神经网络在无网格求解复杂边界与非线性问题中的能力;③对比不同神经网络结构对求解精度与收敛速度的影响,推动PINNs在工程实际中的落地应用。; 阅读建议:建议读者结合所提供的PyTorch代码逐模块分析网络构建、能量泛函定义、边界条件施加及训练流程设计,深入理解物理约束与机器学习模型的融合机制,并鼓励在自定义问题中调整网络参数、采样策略与损失权重以优化性能。
【重要提示】本资源设置为0积分下载,若非0积分请勿轻易下载 亲爱的CSDN用户: 首先感谢你点进这个资源页面。我需要提前说明一个重要情况: 本资源原本已设置为“0积分下载”,即作者希望完全免费共享。但CSDN平台有时会根据文件的下载热度、文件大小、用户权限等因素,自动将部分资源的积分调整为非0数值(如1积分、2积分、5积分等)。这是平台系统的自动行为,而非作者本人的设定。 因此,如果你当前看到该资源的下载所需积分不是0(例如显示为1、2、3……),请谨慎决定是否下载。 如果你按照非0积分支付并下载后发现资源内容不符合预期、链接失效,或者实际上该资源本应是免费的,作者无法为此承担积分损失或退还操作。强烈建议:仅在页面显示为0积分时进行下载。 另外,本资源描述中并未直接提供具体的下载地址或外部链接,因为它本身是一个通过CSDN官方上传通道提交的文件/内容包。如果你看到描述中没有外部网盘地址,这是正常的——资源文件应通过CSDN内置的“下载”按钮获取。若因平台积分显示异常导致你支付了积分,请优先联系CSDN客服咨询积分退还政策,作者没有权限修改平台自动设定的积分值。 感谢你的理解与支持。技术分享本应开放,但受限于平台规则,特此提醒如上。祝学习进步!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值