• bzoj 5123: [Lydsy1712月赛]线段树的匹配


        设f[0/1][x]为区间[1,x]的根向下 不选(0)或者选(1)  的dp pair<最优值,方案数>。

        可以很容易的发现总状态数就是log级别的,因为2*n 与 (2*n+1 或者 2*n-1) 向下有很多重叠,记忆化搜索即可。

       

        初始化的话 f[0][1] = {0,1}, f[1][1] = {0,0} ,切记后者的方案数不能为1,不仅与事实不符,也会与前者重叠。

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    using namespace std;
    using namespace std::tr1;
    #define ll long long
    const int ha=998244353;
    inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
    struct node{
    	ll M; int S;
    	node operator +(const node &u)const{
    		node r=u;
    		if(M>r.M) r=*this;
    		else if(M==r.M) ADD(r.S,S);
    		return r;
    	}
    	node operator *(const node &u)const{
    		return (node){M+u.M,S*(ll)u.S%ha};
    	}
    }A,B;
    unordered_map<ll,node> f[2];
    
    void dp(ll x){
    	if(f[0].count(x)) return;
    	ll mid=x>>1;
    	dp(mid),dp(x-mid);
    	
    	f[0][x]=(f[0][mid]+f[1][mid])*(f[0][x-mid]+f[1][x-mid]);
    	f[1][x]=f[0][mid]*f[1][x-mid]*A+f[1][mid]*f[0][x-mid]*A+f[0][mid]*f[0][x-mid]*B;
    }
    
    int main(){
    	f[0][1]=(node){0,1},f[1][1]=(node){0,0};
    	A=(node){1,1},B=(node){1,2};
    	ll n; scanf("%lld",&n),dp(n);
    	node ans=f[0][n]+f[1][n];
    	printf("%lld %d
    ",ans.M,ans.S);
    	return 0;
    }
    

      

  • 相关阅读:
    Android入门第六篇之ListView (一)
    mysql触发器的作用及语法
    查询记录时rs.previous()的使用
    Microsoft Visual C++ Runtime Library Runtime Error的解决的方法
    Ubuntu中编译链接Opencv应用的简便方式
    24点经典算法
    CMS系统简介(从简介到使用)
    编程学习资源
    Django是什么
    Thinkphp中的自动验证
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8939673.html
Copyright © 2020-2023  润新知