zoukankan      html  css  js  c++  java
  • [BZOJ4135][FJOI2015]世界树

    [BZOJ4135][FJOI2015]世界树

    describe

    奥丁杀死的巨人伊米尔后,从伊米尔的尸体上生长出来一株巨大的梣树,它是整个宇宙的核心,被称为世界之树,这个巨木的枝干构成了整个世界,它被神秘的奥术力量所守护。
    奥丁发现,世界树的每个节点至多有两棵子树,其蕴含的奥术力量是子树奥术力量的最大值+1,如果一个节点没有子树,其奥术力量为1,这些节点被称为“源”。
    世界树在悠长的岁月里形成了奇妙的魔法平衡,具体来说,它的左子树与右子树的奥术力量的差的绝对值不会超过1。若一个节点只有一棵子树(不妨设为左子树),则右子树的奥术力量视为0。
    现在奥丁想知道,在n个节点的世界树中,最高和最低的两个“源”(即叶子节点)的深度差最大是多少?
    Input
    第一行一个整数T,表示数据组数。
    以下T行,每行一个整数n表示世界树的节点数。
    Output
    T行,每行一个整数表示任意两个“源”的奥术力量的差的最大值。
    HINT
    对于100%的数据,1 <= n <= 10^10000, T <= 50
    

    solution

    设 $f(n)$ 为$n$个点时的答案。显然$f(n) leq f(n+1),n geq 6$[1]

    考虑求满足$f(n) = h$时最小的$n$。考虑最低点深度为$x$(从0开始),那么答案最多为$x$。

    此时前$x$层都是满二叉树,元素个数有$2^x-1$,其他层的元素个数设为$g(x)$,则有$g(x) = g(x-1)+g(x-1)+2^{x-1}+g(x-2)+g(x-3)+ dots + g(0) = 3g(x-1)-g(x-2)+2^{x-2}$

    设$h(x)$为答案为$x$时最小需要多少个点,则
    $$
    h(x) = g(x)+2^x-1 = 3h(x-1)-h(x-2)-3*2{x-1}+2{x-2}+2+2{x-2}+2x-1
    $$
    $$
    h(x) = 3h(x-1)-h(x-2)+1
    $$
    $$
    h(0) = 1,h(1) = 4
    $$

    为了方便处理,我们有:
    $$
    h(x) +1= 3h(x-1)-h(x-2)+1+3-1-1
    $$
    即:
    $$
    (h(x) +1)= 3*(h(x-1)+1)-(h(x-2)+1)
    $$

    于是只要求最大的$x$使得$h(x) leq n$即可。预处理$h(2^x)$然后对答案二进制拆分即可。

    复杂度$O(Tlog_2^2 nlog_2{log_2 n})$。需要压位高精度(应该可以法法塔)。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 3305,mod = 100000000;
    char s[20100];
    struct Lint{
    	int len,a[N];
    	bool flag;
    	Lint(){}
    	Lint(int p){
    		len = 0;
    		if (p >= 0) {a[0] = p;flag = 0;}
    		else{a[0] = -p;flag = 1;}
    	}
    	void write(){
    		for (int i = len;i >= 0;i--)
    			printf("%.8d",a[i]);
    		printf("
    ");
    	}
    }n;
    void read(){
    	gets(s);
    	int len = strlen(s);
    	n.len = -1;
    	for (int i = len-1;i >= 0;i-=8){
    		int u = 0,v = 1;
    		for (int j = 0;j < 8 && i-j >= 0;j++){
    			u += v*(s[i-j]-'0');
    			v = v * 10;
    		}
    		n.a[++n.len] = u;
    	}
    	if (n.len < 0) {
    		n.len = 0;
    		n.a[0] = 0;
    	}
    }
    struct Matrix{
    	Lint a[2][2];
    }pw[20],ans,I;
    Lint operator * (const Lint &A,const Lint &B){
    	ll a[N];Lint C;
    	C.len = A.len+B.len;
    	if (A.len == 1 && A.a[0] == 0) return Lint(0);
    	if (B.len == 1 && B.a[0] == 0) return Lint(0);
    	for (int i = 0;i <= C.len+1;i++) a[i] = 0;
    	for (int i = 0;i <= A.len;i++)
    		for (int j = 0;j <= B.len;j++)
    			a[i+j] += (ll)A.a[i]*B.a[j];
    	for (int i = 0;i <= C.len;i++){
    		a[i+1] += a[i]/mod;
    		a[i] %= mod;
    	}
    	if (a[C.len+1] > 0) C.len++;
    	for (int i = 0;i <= C.len;i++) C.a[i] = a[i];
    	C.flag = A.flag ^ B.flag;
    	return C;
    }
    bool operator <= (const Lint &A,const Lint &B){
    	if (A.len < B.len) return 1;
    	if (A.len > B.len) return 0;
    	for (int i = A.len;i >= 0;i--){
    		if (A.a[i] > B.a[i]) return 0;
    		if (A.a[i] < B.a[i]) return 1;
    	}
    	return 1;
    }
    Lint add(Lint A,Lint B){
    	Lint C;
    	C.len = A.len+B.len+1;
    	for (int i = 0;i <= C.len;i++) C.a[i] = 0;
    	if (A.flag == B.flag){
    		C.flag = A.flag;
    		for (int i = 0;i <= A.len;i++) 
    			C.a[i] = A.a[i];
    		for (int i = 0;i <= B.len;i++)
    			C.a[i] += B.a[i];
    		for (int i = 0;i <= C.len;i++)
    			if (C.a[i] >= mod){
    				C.a[i] -= mod;
    				C.a[i+1]++;
    			}
    		while (C.len && C.a[C.len] == 0) C.len--;
    	}
    	else{
    		if (A <= B) swap(A,B);
    		C.flag = A.flag;
    		for (int i = 0;i <= A.len;i++) 
    			C.a[i] = A.a[i];
    		for (int i = 0;i <= B.len;i++) 
    			C.a[i] -= B.a[i];
    		for (int i = 0;i <= A.len;i++)
    			if (C.a[i] < 0){
    				C.a[i] += mod;
    				C.a[i+1]--;
    			}
    		C.len = A.len;
    		while (C.len && C.a[C.len] == 0) C.len--;
    	}
    	return C;
    }
    Matrix operator * (const Matrix &A,const Matrix &B){
    	Matrix C;
    	C.a[0][0] = C.a[0][1] = C.a[1][0] = C.a[1][1] = Lint(0);
    	for (int i = 0;i < 2;i++) 
    		for (int j = 0;j < 2;j++)
    			for (int k = 0;k < 2;k++)
    				C.a[i][j] = add(C.a[i][j],A.a[i][k]*B.a[k][j]);
    	return C;
    }
    
    int T;
    int main(){
    	scanf("%d",&T);gets(s);
    	I.a[0][0] = Lint(2);I.a[0][1] = Lint(5);
    	pw[0].a[0][0] = Lint(0);pw[0].a[0][1] = Lint(-1);
    	pw[0].a[1][0] = Lint(1);pw[0].a[1][1] = Lint(3);
    	for (int i = 1;i <= 15;i++)
    		pw[i] = pw[i-1]*pw[i-1];
    	while (T--){
    		read();
    		if (n.len == 0 && n.a[0] == 6){
    			puts("0");
    			continue;
    		}
    		if (n.len == 0 && n.a[0] <= 3){
    			puts("0");
    			continue;
    		}
    		n = add(n,Lint(1));
    		
    		ans = I;int cnt = 0;
    		for (int i = 15;i >= 0;i--){
    			Matrix u = ans * pw[i];
    			if (u.a[0][0] <= n){
    				ans = u;
    				cnt += 1<<i;
    			}
    		}
    		printf("%d
    ",cnt);
    	}
    	return 0;
    }
    

    1. 可以证明当n一定大时这个式子是成立的,反例有n=6 ↩︎

  • 相关阅读:
    我非要捅穿这 Neutron(三)架构分析与代码实现篇(基于 OpenStack Rocky)
    我非要捅穿这 Neutron(二)上层资源模型篇
    $('.one + div')选取class为one的下一个元素
    15分钟,教你用Python爬网站数据,并用BI可视化分析!
    $("div span")选取里的所有的元素
    根据给定的元素名匹配元素
    根据给定的类名匹配元素
    根据给定的id匹配一个元素
    想创业,请问有没有投资小的项目?
    Vue组件间的通信
  • 原文地址:https://www.cnblogs.com/victbr/p/6735439.html
Copyright © 2011-2022 走看看