Codeforces Global Round 2 E. Pavel and Triangles

本文探讨了一道算法题,即如何使用不同长度的棍子(长度为2的幂次方)组成尽可能多的三角形。通过分析输入的棍子数量,采用贪心算法策略,实现了最大数量的三角形构建,同时确保每个棍子最多被用于一个三角形。

E. Pavel and Triangles
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Pavel has several sticks with lengths equal to powers of two.

He has a0 sticks of length 20=1, a1 sticks of length 21=2, …, an−1 sticks of length 2n−1.

Pavel wants to make the maximum possible number of triangles using these sticks. The triangles should have strictly positive area, each stick can be used in at most one triangle.

It is forbidden to break sticks, and each triangle should consist of exactly three sticks.

Find the maximum possible number of triangles.

Input
The first line contains a single integer n (1≤n≤300000) — the number of different lengths of sticks.

The second line contains n integers a0, a1, …, an−1 (1≤ai≤109), where ai is the number of sticks with the length equal to 2i.

Output
Print a single integer — the maximum possible number of non-degenerate triangles that Pavel can make.

Examples
inputCopy
5
1 2 2 2 2
outputCopy
3
inputCopy
3
1 1 1
outputCopy
0
inputCopy
3
3 3 3
outputCopy
3
Note
In the first example, Pavel can, for example, make this set of triangles (the lengths of the sides of the triangles are listed): (20,24,24), (21,23,23), (21,22,22).

In the second example, Pavel cannot make a single triangle.

In the third example, Pavel can, for example, create this set of triangles (the lengths of the sides of the triangles are listed): (20,20,20), (21,21,21), (22,22,22).

题目是说给你n个数,你可以进行两种操作,一种是把一个数减去3,另一种是把对任意的i<j,把ai减去1,把aj减去2。但所有的数都不能减到小于0。
用两个变量,ans记录答案,cnt记录我们选了多少个当前减2,前面任选一个减1。我们考虑从后往前贪心,如果当前值为1,那么如果cnt有值,那么我们就–cnt,++ans。否则,如果当前值ai是偶数,那么我们拿走ai/2个2,也就是cnt+=ai/2,ans+=ai/2,如果当前值ai是奇数,那么我们先拿走一个3,也就是++ans,ai-=3,然后ai就变成了偶数,就按照之前描述的操作。贪心完了以后我们发现我们还需要拿走cnt个1,但我们现在已经把所有的ai清零了,所以我们得从ans里面扣除一部分将cnt补成负数,因为一次操作会使整个数组的所有数之和减3,也就是说–ans可以让cnt-=3,我们将需要减去的cnt减去即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
typedef long long ll;
ll ans,cnt;
int z[maxn];
int n;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d", z + i);
    for (int i = n; i >= 1; --i)
    {
        if (z[i] % 2 == 0)
        {
            ans += z[i] / 2;
            cnt += z[i] / 2;
        }
        else if (z[i] == 1)
        {
            if (cnt)
                --cnt;
        }
        else
        {
            ++ans;
            z[i] -= 3;
            ans += z[i] / 2;
            cnt += z[i] / 2;
        }
    }
    if (cnt)
        ans -= (cnt + 2) / 3;
    printf("%lld\n", ans);
    return 0;
}

 

### 关于 Codeforces Round 1022 (Div. 2) E 题 (Spruce Dispute) 的解法 #### 题目概述 题目要求判断是否可以从给定的二叉树中删除一些节点,使得剩下的树满足特定条件。具体来说,需要确保每个非叶子节点至少有两个子节点[^1]。 #### 解题思路 该问题可以通过深度优先搜索(DFS)来解决。主要思想是通过递归地遍历树的每个节点,并检查其子节点数量是否满足条件。如果某个节点不满足条件,则将其标记为可删除,并继续向上层传播这一信息。 以下是具体的实现步骤和代码示例: #### 实现方法 首先,构建一个邻接表来表示树的结构。然后从根节点开始进行深度优先搜索,检查每个节点的子节点数量是否满足条件。如果不满足,则将该节点视为“无效”,并将其状态传递给父节点。 ```python # Python 实现代码 from collections import defaultdict def dfs(node, parent, tree): # 初始化当前节点的有效子节点数量 valid_children = 0 # 遍历当前节点的所有子节点 for child in tree[node]: if child != parent: is_valid = dfs(child, node, tree) if is_valid: valid_children += 1 # 如果当前节点是非叶子节点且有效子节点少于2个,则返回False if len(tree[node]) > 1 and valid_children < 2: return False # 否则返回True,表示当前节点可以保留 return True def can_form_spruce(n, edges): # 构建邻接表 tree = defaultdict(list) for u, v in edges: tree[u].append(v) tree[v].append(u) # 从根节点(假设为1)开始进行DFS return dfs(1, -1, tree) # 示例输入 n = 5 edges = [(1, 2), (1, 3), (2, 4), (2, 5)] result = can_form_spruce(n, edges) print("Yes" if result else "No") ``` #### 复杂度分析 - **时间复杂度**:O(n),其中 n 是节点的数量。每个节点仅被访问一次。 - **空间复杂度**:O(n),用于存储邻接表和递归调用栈。 #### 注意事项 在实现过程中需要注意以下几点: 1. 确保正确处理树的输入格式,例如边的列表。 2. 在 DFS 过程中避免重复访问父节点。 3. 对于特殊情况(如只有一个节点或所有节点都是叶子节点),需要单独处理[^1]。 #### 结论 通过上述方法,可以高效地判断是否可以从给定的二叉树中删除一些节点以满足题目要求。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值