zoukankan      html  css  js  c++  java
  • [LuoguP4808][CCC 2018]平衡树(数论分块+记忆化搜索)(有复杂度证明)

    [LuoguP4808][CCC 2018]平衡树(数论分块+记忆化搜索)(有复杂度证明)

    题面

    我们定义「完美平衡树」如下:
    每棵完美平衡树都有一个正整数权值。权值为 (1) 的完美平衡树为只含有 (1) 个节点的树。否则,这棵树的权值为 (w(wge2)),则这棵树为一棵含有 (k(2le kle w)) 棵子树的有根树。所有的 (k) 棵子树都必须是相同的,且它的所有 (k) 棵子树必须完全相同,且自身是完美平衡的。

    特别地,所有 (k) 棵子树权值必须相同。它们的权值必须为 (leftlfloorfrac{w}{k} ight floor) 。例如,如果一棵权值为 (8) 的完美平衡树有 (3) 棵子树,那么每棵子树的权值为 (2),因为 (2+2+2=6le8)

    给定 (N(1leq n leq 10^9)),求出权值为 (N) 的完美平衡树的数量。

    分析

    简化版题面.已知(f_1=1,f_n=sum_{i=2}^n f_{lfloorfrac{n}{i} floor}(n geq 2)),求(f_n(n leq 10^9))

    首先,可以利用数论分块把(f_{lfloorfrac{n}{i} floor})的枚举优化到(O(sqrt n)),然后注意到(f_n)用到的状态不多,可以用记忆化搜索,于是就跑过了。

    时间复杂度(O(n^{frac{3}{4}})),证明如下:
    由于(lfloorfrac{n}{xy} floor=lfloor frac{lfloorfrac{n}{x} floor}{y} floor),那么用到的状态数只有根据数论分块(n)分出的(sqrt{n})个,那么可以写出递归式

    [T(n)=sum_{i=2}^n T(lfloor frac{n}{i} floor)+sqrt{n} ]

    其中(sqrt{n})是累加的复杂度. 那么有

    [T(n)=sum_{i=2}^{sqrt{n}} (T(i)+T(lfloor frac{n}{i} floor))+sqrt{n} ]

    代入并展开一层,出现的和式是高阶小量,可忽略

    [egin{aligned}T(n)&=sum_{i=2}^{sqrt{n}}(sqrt{i}+sqrt{lfloorfrac{n}{i} floor})+sqrt{n} \ &geq sum_{i=2}^{sqrt{n}}(2sqrt{sqrt{i}cdot sqrt{frac{n}{i}})}+sqrt{n} \ &=2sqrt{sqrt{n}}+sqrt{n} \ &=O(n^{frac{3}{4}})end{aligned} ]

    注意到这恰好是杜教筛在没有线性预处理的复杂度。由于这个函数无法线性筛,所以不能做到杜教筛的(O(n^{frac{2}{3}}))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<map> 
    #define maxn 10000000 
    using namespace std;
    typedef long long ll;
    //小的n用数组,大的n用map记录状态,卡常
    ll f[maxn+5];
    map<ll,ll>mf; 
    ll dfs(int n){
    	if(n==1) return 1;
    	if(n<=maxn&&f[n]) return f[n];
    	if(mf.count(n)) return mf[n];  
    	ll ans=0; 
    	for(int l=2,r;l<=n;l=r+1){
    		r=n/(n/l);
    		ans+=dfs(n/l)*(r-l+1);
    	}
    	if(n<=maxn) f[n]=ans;
    	else mf[n]=ans;
    	return ans;
    }
    int main(){
    #ifndef LOCAL
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);
    #endif 
    	int n; 
    	scanf("%d",&n);
    
    	printf("%lld
    ",dfs(n));
    }
    
  • 相关阅读:
    C++ 对象模型学习记录(2) 第3章 data语义学
    C++ 对象模型学习记录(1) 第2章 构造函数语义学
    C ++ 对象模型学习记录(4) function 语义学 (未完待续)
    C++ 对象模型学习记录(3) 第1章 关于对象(未完)
    设计模式复习 之 代理模式
    大数运算
    effective C ++ 学习笔记之 item 31 将文件间的编译依赖关系降至最低(未完成)
    Java 复习 之1 多线程
    SQL中char varchar nchar nvarchar ntext区别和使用(资料汇总)
    .Net中的加密解密
  • 原文地址:https://www.cnblogs.com/birchtree/p/14081164.html
Copyright © 2011-2022 走看看