zoukankan      html  css  js  c++  java
  • 【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索

    题目描述

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

    $nle 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
    " , ans.x , ans.y);
    	return 0;
    }
    
  • 相关阅读:
    wepack性能优化-contenthash(缓存)
    webpack优化系列-oneOf
    webpack性能优化-source-map
    webpack性能优化-HMR
    vue__之路由懒加载
    vue__之ref的作用
    圆面积和球体积
    算法思想
    看完com本质论第一章
    windows消息机制
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8182253.html
Copyright © 2011-2022 走看看