【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索

题目描述

求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数。

$n\le 10^{18}$


题解

树形dp+记忆化搜索

设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根节点的最大匹配&方案数,$g[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配不选择根节点的最大匹配&方案数。那么这是一个很普通的树形dp。

注意到区间长度相等的线段树的结果是一样的,且每层至多有两种区间长度不同的区间(参考 这题 ),因此直接以区间长度为状态进行记忆化搜索即可。

这里偷懒使用了map,时间复杂度 $O(\log^2 n)$

#include <map>
#include <cstdio>
#define mod 998244353
using namespace std;
typedef long long ll;
struct data
{
	ll x , y;
	data() {}
	data(ll a , ll b) {x = a , y = b;}
	data operator+(const data &a)const {return data(x + a.x , y * a.y % mod);}
	data operator*(const data &a)const
	{
		if(x > a.x) return *this;
		if(x < a.x) return a;
		return data(x , (y + a.y) % mod);
	}
};
struct node
{
	data f , g;
	node() {}
	node(data a , data b) {f = a , g = b;}
};
map<ll , node> mp;
node dfs(ll n)
{
	if(mp.find(n) != mp.end()) return mp[n];
	node l = dfs(n - (n >> 1)) , r = dfs(n >> 1);
	return mp[n] = node((l.f + r.g + data(1 , 1)) * (l.g + r.f + data(1 , 1)) * (l.g + r.g + data(1 , 2)) , (l.f + r.f) * (l.f + r.g) * (l.g + r.f) * (l.g + r.g));
}
int main()
{
	mp[1] = node(data(-1 , 0) , data(0 , 1));
	ll n;
	scanf("%lld" , &n);
	node tmp = dfs(n);
	data ans = tmp.f * tmp.g;
	printf("%lld %lld\n" , ans.x , ans.y);
	return 0;
}

 

转载于:https://www.cnblogs.com/GXZlegend/p/8182253.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值