首页 > 其他分享 >砍树

砍树

时间:2024-11-11 14:00:23浏览次数:1  
标签:int tree mid maxh 砍树 printf baka

P1873砍树

题目

要砍M米长木材,需找到伐木机锯片的最大整数高度H,保证能得到至少M米木材,锯掉树比H高的部分,得到锯下部分木材,且再升高1米就得不到M米木材

1≤N≤106,1≤M≤2×10e9,树的高度 ≤4×10e5 ,所有树的高度总和 >M

INPUT

第 1 行 2 个整数 N 和 M,N表示树木的数量,M表示需要的木材总长度

第 2 行 N 个整数表示每棵树的高度

OUTPUT

1 个整数,表示锯片的最高高度

Example Input

4 7
20 15 10 17
5 20
4 42 40 26 46

Example Output

15
36

+++

[!TIP]

利用二分查找 在每次循环中,计算中间值mid(锯片高度)然后遍历所有树木,对高于mid的树计算锯下部分的长度并累加得到 sum再根据 sum与M的比较结果来调整查找范围

时间复杂度:O(nlog)

[!WARNING]

二分查找使用int mid = (baka + maxh) / 2;可能会溢出,不能确保向上取整或死循环,应该用int mid = maxh + (baka - maxh + 1) / 2;来避免类似情况发生

用时 内存
385ms 4.23MB
#include <cstdio>
#include <vector>

using namespace std;

int main() 
{
    int n, m;
    scanf("%d %d", &n, &m);//更快

    vector<int> tree(n);
  //或者int tree[1145141];
  
    for (int i = 0; i < n; i++) 
    {
        scanf("%d", &tree[i]);
    }

    int maxh = 0;
    int baka = 11451419;
    
    //二分找合适高度
    while (maxh < baka)//(即left < right)
    {
        int mid = maxh + (baka - maxh + 1) / 2;
        //避免整数溢出和死循环
        long long sum = 0;
        
        // 计算剩树高度和
        for (int i = 0; i < n; i++) 
        {
            if (tree[i] > mid) 
            {
                sum += tree[i] - mid;
            }
        }

        if (sum >= m) 
        {
            maxh = mid;
        } 
        else 
        {
            baka = mid - 1;
        }
    }

    printf("%d\n", maxh);

    return 0;
}

[!TIP]

同时可以用algorithm(max)预处理最大值减少二分查找范围,提高效率

用时 内存
370ms 4.22MB
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

int main() 
{
    int n, m;
    scanf("%d %d", &n, &m);

    vector<int> tree(n);
    int fumo = 0;

    for (int i = 0; i < n; i++) 
    {
        scanf("%d", &tree[i]);
        fumo = max(fumo, tree[i]);
    }

    int maxh = 0;
    int baka = fumo; 
    while (maxh < baka) 
    {
        int mid = maxh + (baka - maxh + 1) / 2;
        long long sum = 0;
        
        for (int i = 0; i < n; i++) 
        {
            if (tree[i] > mid) 
            {
                sum += tree[i] - mid;
            }
        }

        if (sum >= m) 
        {
            maxh = mid;
        } 
        else 
        {
            baka = mid - 1;
        }
    }

    printf("%d\n", maxh);

    return 0;
}

[!TIP]

在题解里看到一个用sort排序再从后往前查找的方法,这里做一下记录

假设已砍过了i棵树(树由高到低排),那此时被砍过的i棵树的高度均等于第i+1棵树的高度

再砍一棵树(砍第i+1棵)后获得的新高度为(第i+1棵树的高度-第i+2棵树的高度)*(i+1)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int tree[1000001];
int n, m;

int main() {
    int i, num, ans;
    long long sum;

    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; i++) {
        scanf("%d", &tree[i]);
    }

    // 对树的高度进行升序排序
    sort(tree + 1, tree + n + 1);

    sum = 0;
    num = n;
    // 计算累计的剩余树木总高度,直到超过m
    while (sum < m) {
        sum += (tree[num] - tree[num - 1]) * (n - num + 1);
        num--;
    }
    num++;

    ans = tree[num - 1] + (sum - m) / (n - num + 1);

    printf("%d\n", ans);

    return 0;
}

[!TIP]

还有面向结果编程艹

#include<cstdio>
using namespace std;
int main()
{
	int n;
	scanf("%d",&n);
	if(n==10) printf("23");
	if(n==750444) printf("10662");
	if(n==999888) printf("7994");
	if(n==300) printf("114");
	if(n==1000) printf("3961");
	if(n==10000) printf("70");
	if(n==30000) printf("237704");
	if(n==100000) printf("86792");
	if(n==300001) printf("47429");
	if(n==555444) printf("19879");
}

标签:int,tree,mid,maxh,砍树,printf,baka
From: https://www.cnblogs.com/gailixia/p/18539539

相关文章

  • 2-60. 实现斧子砍树的功能
    调整树的碰撞体修改GridMapManager修改Crop修改CropManager修改Crop修改CursorManager修改GridMapManager修改Player现在有个问题,人物从上面砍树的时候,会面向上面修复Bug不知道为什么,我现在做的东西和老师的偏差有点大,我就按自己的理解来修复bug了首先......
  • P1873 [COCI 2011/2012 #5] EKO / 砍树
    题目链接:一、本题为什么能想到利用二分解决?\(1.\)有单调性提高伐木机的高度,显然地,得到的木头会减少。同样地,放低得到的木头会增多。而正因为答案有单调性,所以我们可以使用二分。\(2.\)数据范围大如果采用暴力枚举,时间复杂度为\(O(n\cdotm)\)会超时。用二分优化后时间......
  • 【洛谷】P1873 [COCI 2011/2012 #5] EKO / 砍树 (二分)
    题目描述见:P1873思路比较明确qwq因为答案显然满足单调性:当x超过某个数一定是错的(收集的木材大于m),而小于x一定是对的,并且x是从0一直递增。故我们只需二分法找到x。直接看代码吧qwq精髓是check函数直接模拟题目要求ww#include<iostream>usingnamespacestd;#defineMAXN100......
  • 蓝桥杯省赛真题(砍树 整数删除 景区导游 翻转硬币)
    蓝桥杯省赛真题(砍树整数删除景区导游翻转硬币)四道比较难的题(题解是官方提供的)砍树(树上差分)https://www.lanqiao.cn/problems/3517/learning/解题思路在这个问题中,我们需要找到一条边,砍掉它之后,所有给出的节点对\((a_i,b_i)\)之间都不再连通。换言之,这条边应是所有\((......
  • [COCI2011-2012#5] EKO / 砍树
    [COCI2011-2012#5]EKO/砍树题目描述伐木工人Mirko需要砍\(M\)米长的木材。对Mirko来说这是很简单的工作,因为他有一个漂亮的新伐木机,可以如野火一般砍伐森林。不过,Mirko只被允许砍伐一排树。Mirko的伐木机工作流程如下:Mirko设置一个高度参数\(H\)(米),伐木机升起一个......
  • 砍树
    砍树给定一棵由$n$个结点组成的树以及$m$个不重复的无序数对$(a_1,b_1),(a_2,b_2),\ldots,(a_m,b_m)$,其中$a_i$互不相同,$b_i$互不相同,$a_i\neb_j\(1\leqi,j\leqm)$。小明想知道是否能够选择一条树上的边砍断,使得对于每个$(a_i,b_i)$满足$a_i$和$b_i$不......
  • 洛谷P873 砍树
    洛谷P873砍树原题链接#include"iostream"#include"algorithm"usingnamespacestd;intn,maxx,tree[1000001]={0};boolcheck(intx){longlongsum=0;for......
  • 675. 为高尔夫比赛砍树
    题目描述给了一个mxn的森林矩阵,里面的数字为0代表障碍,1代表平地,>1的数代表树题目要求你必须按照树的高度从低到高砍树,问砍完的需要最少多少步?f1-遍历排序+bfs基本分析......
  • P3874 砍树 题解
    前置树形dp,二分。题意本质上是一个树上背包,需要选不少于\(k\)个物品,每个物品有一个重量\(w\)和价值\(v\),求性价比最大值。分析既然是性价比,显然是分数规划。先......
  • 暑假集训五[星际旅行, 砍树, 超级树, 求和]
    暑假集训5星际旅行这个题刚看我觉得很ex,没事思路,就跳了,然后就去欺负\(T4\)了后来别的不会做,然后回来肝它...就肝出来了...对了,注意开\(longlong\)首先转化一下题意,我......