CF 337E(Divisor Tree-枚举树节点的父亲)

本文介绍了一种算法,用于构建包含特定整数集合的最小分拆树。该算法通过枚举树结构来寻找最优解,并确保每个输入整数至少出现在树的一个节点上。文章还提供了实现这一算法的具体代码。

E. Divisor Tree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

divisor tree is a rooted tree that meets the following conditions:

  • Each vertex of the tree contains a positive integer number.
  • The numbers written in the leaves of the tree are prime numbers.
  • For any inner vertex, the number within it is equal to the product of the numbers written in its children.

Manao has n distinct integers a1, a2, ..., an. He tries to build a divisor tree which contains each of these numbers. That is, for each ai, there should be at least one vertex in the tree which contains ai. Manao loves compact style, but his trees are too large. Help Manao determine the minimum possible number of vertices in the divisor tree sought.

Input

The first line contains a single integer n (1 ≤ n ≤ 8). The second line contains n distinct space-separated integers ai (2 ≤ ai ≤ 1012).

Output

Print a single integer — the minimum number of vertices in the divisor tree that contains each of the numbers ai.

Sample test(s)
input
2
6 10
output
7
input
4
6 72 8 4
output
12
input
1
7
output
1
Note

Sample 1. The smallest divisor tree looks this way:

Sample 2. In this case you can build the following divisor tree:

Sample 3. Note that the tree can consist of a single vertex.



NOI就因为这个少拿10分了啊。。。现在又因为这个掉Rating了吖囧。。。。

首先明确一点——O(n!) 在n≤10时可过,O(2^n)在n≤20时可过。。。

然后枚举树(都懂得。。)


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (8+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
int n,fa[MAXN]={0},p[MAXN]={0};
ll a[MAXN],a2[MAXN],ans=INF;
void dfs(int l)
{
	if (l==n+1)
	{
	//	For(i,n) cout<<a2[i]<<' ';cout<<endl;
	//	For(i,n) cout<<fa[i]<<' ';cout<<endl;
		
		ll tot=0;
		For(i,n) if (!((!p[i])&&fa[i])) tot++; 
		bool b=0;
		For(i,n-1) if (!fa[i]) {b=1;break;}
		tot+=b;
		For(i,n) tot+=p[i]*!(bool)fa[i];
		ans=min(ans,tot);
		
	//	cout<<tot<<endl;
		/*
		if (tot==9) 
		{
			cout<<'d';
		}*/
		return;
	}
	fa[l]=0;dfs(l+1);
	Fork(i,l+1,n) if (a2[i]%a[l]==0) fa[l]=i,a2[i]/=a[l],dfs(l+1),a2[i]*=a[l];	
}
int main()
{
//	freopen("Divisor.in","r",stdin);
	cin>>n;
	For(i,n) cin>>a[i];
	sort(a+1,a+1+n);
	For(i,n) 
	{
		ll x=a[i];
		for(ll j=2;j*j<=x;j++)
			while (x%j==0) p[i]++,x/=j;
		if (x>1) p[i]++,x=1;
		if (p[i]==1) p[i]--;	
	}
	memcpy(a2,a,sizeof(a));
	dfs(1);cout<<ans<<endl;
	
	return 0;
}




<think>我们正在回答关于B+Tree索引优点的问题。根据引用内容,我们知道B+Tree索引是MySQL等数据库系统中常用的索引结构。与Hash索引、二叉搜索树(如红黑树)相比,B+Tree具有显著优势。下面我将结合引用内容,详细说明B+Tree索引的优点。 ### 1. **树高度可控,适合磁盘存储** - B+Tree是一种多路平衡搜索树(引用[2]中提到),每个节点可以有多个子节点(通常为几百个)。这相比于二叉搜索树(每个节点最多两个子节点)大大降低了树的高度。 - 例如,对于千万级别的数据量,B+Tree的高度通常维持在3-5层(引用[2]),而红黑树的高度可能达到几十层。树高度低意味着磁盘I/O次数少(因为每次访问节点可能对应一次磁盘读取),这对数据库性能至关重要。 - 数学表达:设B+Tree的阶数为$m$(即每个节点最多$m$个子节点),则树高$h$与数据量$N$的关系为: $$ h \approx \log_m N $$ 当$m$较大时,$h$远小于二叉树的$O(\log_2 N)$。 ### 2. **范围查询高效** - B+Tree的数据全部存储在叶子节点,且叶子节点间通过指针连接成有序链表(引用[2])。这使得范围查询(如`WHERE id BETWEEN 100 AND 200`)非常高效:只需定位到起始值,然后顺序遍历链表即可。 - 相比之下,Hash索引仅支持等值查询(引用[1][3]),无法高效处理范围查询;二叉搜索树虽有序,但范围查询需要多次回溯父节点,效率较低。 ### 3. **数据有序性,避免全表扫描** - B+Tree索引本身是排序的(引用[2]),因此对于排序操作(`ORDER BY`)、分组操作(`GROUP BY`)以及最值查询(`MAX/MIN`)可以直接利用索引的有序性,避免全表扫描。 - 例如,查询最大值时,只需遍历最右侧叶子节点链表的末尾。 ### 4. **减少磁盘I/O,提高缓存命中率** - B+Tree的非叶子节点仅存储键值(不存储实际数据),因此单个节点可容纳更多键值(引用[2])。这使得非叶子节点可以缓存到内存中,减少磁盘访问。 - 实际数据(或数据指针)仅存在于叶子节点,保证了查询路径长度一致(稳定性能)。 ### 5. **自适应Hash优化(InnoDB特性)** - InnoDB存储引擎在特定条件下会自动将频繁访问的B+Tree索引转换为Hash索引(引用[3]),结合了Hash的等值查询速度和B+Tree的范围查询优势。 ### 6. **对比其他索引的劣势** - **Hash索引**: - 优点:等值查询$O(1)$复杂度(引用[1])。 - 缺点:不支持范围查询、排序;哈希冲突影响性能;内存需求高(引用[3])。 - **二叉平衡树(如红黑树)**: - 优点:查询单个值$O(\log N)$。 - 缺点:树高较大(尤其海量数据时),导致磁盘I/O多;范围查询效率低于B+Tree(引用[2])。 ### 总结 B+Tree索引的核心优势在于**低树高**(减少磁盘I/O)、**有序性**(高效范围查询)和**结构优化**(非叶子节点仅存键值)。这些特性使其成为数据库索引的标准选择。实际应用中,InnoDB的自适应Hash功能进一步提升了高频等值查询的性能[^3]。 §§相关问题§§ 1. B+Tree索引的节点分裂与合并机制如何实现平衡? 2. 在什么场景下应优先选择Hash索引而非B+Tree? 3. InnoDB的自适应Hash索引是如何工作的? 4. 如何通过B+Tree索引优化SQL查询性能? 5. B+Tree索引的页大小对性能有何影响? [^1]: 索引是对数据库表中一列或多列的值进行处理后的一种结构,使用索引可快速访问数据库表中的特定信息。本文主要对Hash索引和B+tree索引的区别做说明。 [^2]: B+树是B-树的加强版,是一种多路平衡搜索树,既然它是多路平衡的,那么就不在像红黑树那样只有2个子节点了,既然有多个子节点,树的高度就可以控制了。 [^3]: 在MySQL中,支持hash索引的是Memory存储引擎。而InnoDB中具有自适应hash功能,hash索引是InnoDB存储引擎根据B+Tree索引在指定条件下自动构建的。</think>### B+Tree索引的核心优势详解 B+Tree索引是数据库系统的核心数据结构,相较于Hash索引、二叉搜索树等结构,其优势体现在以下关键维度: --- #### 1. **树高度可控,减少磁盘I/O** - **多路平衡设计**: B+Tree每个节点可存储多个键值(通常数百个),形成**多路平衡树**。设阶数为$m$,树高$h$与数据量$N$满足: $$ h \approx \log_m N $$ 例如:$m=500$时,10亿数据仅需$h=4$层,而二叉树需$\log_2 N \approx 30$层。 - **磁盘优化**: 数据库以页(通常4KB)为单位读写磁盘。B+Tree节点大小匹配磁盘页,**单次I/O可加载大量键值**,显著减少磁盘访问次数[^2]。 --- #### 2. **高效范围查询** - **叶子节点链表结构**: B+Tree所有数据存储在叶子节点,并通过指针**双向链接**(如图示)。 ```mermaid graph LR A[根节点] --> B[内部节点] A --> C[内部节点] B --> D[叶子节点 10→20→30] B --> E[叶子节点 40→50] D -->|指针| E ``` 范围查询(如`WHERE id BETWEEN 30 AND 50`)只需定位起始叶子节点,沿链表遍历即可[^2]。 - **对比劣势**: - **Hash索引**:仅支持等值查询,无法处理范围扫描[^1]。 - **二叉树**:范围查询需回溯父节点,效率低下。 --- #### 3. **查询性能稳定** - **路径等长特性**: B+Tree所有叶子节点位于同一深度,**任何查询的I/O次数恒等于树高$h$**。 - **对比红黑树**: 红黑树高度不平衡(最深路径可达最短路径2倍),查询性能波动大[^2]。 --- #### 4. **高缓存命中率** - **非叶节点纯索引**: 非叶子节点仅存储键值和子节点指针(**不存实际数据**),使得: - 单节点可容纳更多键值 - 高频访问的根/非叶节点**常驻内存**,减少磁盘访问[^2]。 - **数据局部性**: 叶子节点存储连续数据,顺序访问时**预读机制**可批量加载相邻数据。 --- #### 5. **自适应优化能力(InnoDB)** - **动态Hash转换**: InnoDB监测高频等值查询时,**自动构建自适应Hash索引**,将B+Tree键值映射到Hash表,实现$O(1)$查询[^3]。 - **混合优势**: 保留B+Tree范围查询能力,同时获得Hash的等值查询速度。 --- #### 6. **对比其他索引的劣势总结** | 索引类型 | 等值查询 | 范围查询 | 树高控制 | 磁盘I/O优化 | |----------------|----------|----------|----------|-------------| | **B+Tree** | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | | **Hash** | ⭐⭐⭐⭐⭐ | ❌ | - | ⭐⭐ | | **红黑树** | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐ | | **二叉搜索树** | ⭐⭐⭐ | ⭐ | ❌ | ❌ | > ⭐:优势等级(5星最优);❌:不支持/弱项 --- ### 总结 B+Tree的核心优势在于:**多路平衡控制树高**(减少I/O)、**叶子链表支持高效范围扫描**、**稳定查询路径**及**缓存友好设计**。结合InnoDB的自适应Hash,成为数据库索引的黄金标准。实际应用中,B+Tree在范围查询占比高的场景(如日志分析、时间序列数据)优势尤为显著[^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值