CF735C 数论\平衡树叶子节点的最大深度\贪心\斐波那契\条件归一化

http://codeforces.com/problemset/problem/735/C

题意。。采用淘汰赛制。。只要打输就退出比赛。。而且只有两个选手打过的场数

相差不超过1才能比赛。。最后问你。。最多打几场比赛能决出冠军

那么这个题的做法是。。画图。。观察。。分析

Tip:首先我们观察未知量的形式。。它是一个复合函数的形式。。max(决出冠军的所有可能的比赛方式的场数)

那么我们首先要求括号最里面的东西。。即符合条件的所有可能的比赛方式的场数

那么我们可以画一画

我一开始为了保证比赛能正常进行。。不会像第一个图那样。。由于深度差太多无法比完所有选手。。因而无法决出冠军

所以两两比赛。。这样深度就有保证了。。但是回过头来。。是不是不符合题设最大的场数这个条件呢,这里我当时没法判断

由于我每次都把相邻的两两合并。。所以当然没有发现数量为8的时候。。最大可以为4场比赛

这个应该属于手玩数据的瑕疵?没什么经验。。

但是一旦你注意到了一个基础的事实。。冠军每次和比自己场数低的比能打得比和相同场数的选手多(有可能)。。因为同样都是增加一场比赛,和场数低的选手比

就能消耗更少的选手,那么你就可能需要更多的场次和剩余选手比赛。。

这个贪心策略我当时只是闪过一下。。因为我害怕这种策略无法满足完成比赛的条件。。而且一直没有找到这种策略能过的例子。。并且还有第一个例子挡在我的面前

所以我就放弃了。。题意都没有观察清楚。。

但其实如果你遵循这种策略造成了第一个例子最后剩一个没法比的情况。。那么你就不要和比自己场次低的比。。提升到相等即可符合条件过掉比赛

什么?你担心场次变化?多算几组?一样的好吧。。提升到相等的选手和它比场次不会增加也不会减少。。

那么知道了这个贪心策略之后。。我们可以计算答案了

观察可以得到这是一个斐波那契的结构。。

然后感觉有点迷糊。。

到底怎么统计答案啊

Tip:我们经过硬看之后。。发现图上的这个数字和连边操作的语义是。。生成一个比了某某场次的选手需要消耗多少名选手

那么我们消耗完所有的选手。。就能计算出最多能生成多少场次的选手。。根据这个过程我们用斐波那契去逼近

由于斐波那契的性质。。我们可以知道斐波那契数列可以非常快地收敛于参赛选手的数量

所以当我们分清了图上的过程和语义之后以及有了和谐不能完成比赛的策略和贪心的策略我们就能用ll,快速地统计答案

代码如下

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long ll;
ll n;
ll f[100];
int main(){
    scanf("%I64d",&n);
    f[0]=1;f[1]=2*f[0];
    int i;
    for(i=2;i<=100;++i){
        f[i]=f[i-1]+f[i-2];
        if(f[i]>=n) break;
    }
    if(f[i]>n) i--;
    printf("%d\n",i);
    return 0;
}

由于深度相差小于等于1的节点才能合并。。那么我们就能把它看成是一颗平衡树。。那么题设就是在求这个平衡树的叶子节点的最大深度

时间: 2024-11-09 04:57:18

CF735C 数论\平衡树叶子节点的最大深度\贪心\斐波那契\条件归一化的相关文章

数论--斐波那契额

通项公式: 1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 int main() 5 { 6 double a,n,ans; 7 cin>>n; 8 //n--; //(第一项是0时) 9 a=sqrt(5); 10 ans =(a/5) * (pow( (1+a)/2 ,n) - pow((1-a)/2 ,n)); 11 cout<<ans; 12 return 0; 13 }

二叉树基本操作--创建,三种遍历,叶子节点

虽然二叉树的操作很常见,但是认真写写熟悉很重要,特别是typedef, CreateBiTree(BiTNode** T)指针的操作等等,还有就是创建方法,去实际输入值就知道其中的妙处,为-1时为空节点. #include <iostream> using namespace std; //节点的定义 typedef struct BTNode { int data; BTNode* rChild; BTNode* lChild; }BiTNode, *BiTree; //二叉树的创建,先序创

jquery zTree 查找所有的叶子节点

// 保存所有叶子节点 10 为初始化大小,并非数组上限 var arrayObj = new Array([10]); /* treeNode: 根节点 result: 用于保存叶子节点的数组 */ // 获取所有叶子节点 function getAllLeafNodes(treeNode, result) { if (treeNode.isParent) { var childrenNodes = treeNode.children; if (childrenNodes) { for (va

二叉树权值最大的叶子节点到权值最小的叶子节点的距离

有一棵二叉树,树上每个点标有权值,权值各不相同,请设计一个算法算出权值最大的叶节点到权值最小的叶节点的距离.二叉树每条边的距离为1,一个节点经过多少条边到达另一个节点为这两个节点之间的距离. 给定二叉树的根节点root,请返回所求距离. 真是醉了,看漏了叶子节点. 代码: 1 import java.util.*; 2 3 /* 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right =

先序遍历创建二叉树,对二叉树统计叶子节点个数和统计深度(创建二叉树时#代表空树,序列不能有误)

#include "stdio.h" #include "string.h" #include "malloc.h" #define NULL 0 #define MAXSIZE 30 typedef struct BiTNode      //定义二叉树数据结构 { char data; struct BiTNode *lchild,*rchild; } BiTNode; void preCreate(BiTNode *& T)   /

六:二叉树中第k层节点个数与二叉树叶子节点个数

二叉树中第k层节点个数 递归解法: (1)如果二叉树为空或者k<1返回0 (2)如果二叉树不为空并且k==1,返回1 (3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和 代码如下: int GetNodeNumKthLevel(BinaryTreeNode *pRoot, int k) { if(pRoot == NULL || k < 1) return 0; if(k == 1) return 1; int numLeft = GetNodeN

2013-03-17---二叉树递归,非递归实现(附代码)深度,叶子节点数量,逐行打印二叉树

昨天晚上没有发文章,说来话长啊,昨天不知道是csdn的问题,还是我的问题,我访问了半天,访问不上网站啊,后来12点多了,就睡了.上一篇文章说到了二叉树的先序,中序,后序遍历问题,这次还是说的简单的一点,说计算二叉树的深度,和叶子节点数量 int ceng(Node *pRoot) //计算层数,递归实现 { int left = 0; int right = 0; int res = 0; if (pRoot == NULL) { return 0; } if (pRoot->pLeft !=

求二叉树第K层的节点个数+求二叉树叶子节点的个数

size_t _FindLeafSize(Node* root)     //求二叉树叶子节点的个数    {        //static size_t count = 0;        if (root == NULL)            return 0; if (root->_left == NULL&&root->_right == NULL);        return 1; return _FindLeafSize(root->_right) +

第4章第1节练习题6 二叉树叶子节点链接成单链表

问题描述 设计一个算法,将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head.链接时用叶子节点的右指针来存放单链表指针. 算法思想 题目要求将叶子节点按自左向右的次序连接成一个单链表,因此很容易考虑到的便是将整棵二叉树按照先序或中序或后序的方式遍历一次. 在遍历的过程中对叶子节点单独判断,如果是叶子节点,则将其做一个标识(比如用额外的指针指向该节点),接着遍历下一个叶子节点,遍历到另一个叶子节点后,然后让已被标识的叶子节点的右孩子指向该节点,依次类推便可以实现将叶子节点连接成单链