Codeforces 675C Money Transfers 【思维】 + 675D Tree Construction 【二分】

62 篇文章 0 订阅
60 篇文章 0 订阅

题目链接:Codeforces 675C Money Transfers

C. Money Transfers
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
There are n banks in the city where Vasya lives, they are located in a circle, such that any two banks are neighbouring if their indices differ by no more than 1. Also, bank 1 and bank n are neighbours if n > 1. No bank is a neighbour of itself.

Vasya has an account in each bank. Its balance may be negative, meaning Vasya owes some money to this bank.

There is only one type of operations available: transfer some amount of money from any bank to account in any neighbouring bank. There are no restrictions on the size of the sum being transferred or balance requirements to perform this operation.

Vasya doesn’t like to deal with large numbers, so he asks you to determine the minimum number of operations required to change the balance of each bank account to zero. It’s guaranteed, that this is possible to achieve, that is, the total balance of Vasya in all banks is equal to zero.

Input
The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of banks.

The second line contains n integers ai ( - 109 ≤ ai ≤ 109), the i-th of them is equal to the initial balance of the account in the i-th bank. It’s guaranteed that the sum of all ai is equal to 0.

Output
Print the minimum number of operations required to change balance in each bank to zero.

Examples
input
3
5 0 -5
output
1
input
4
-1 0 1 0
output
2
input
4
1 2 3 -6
output
3
Note
In the first sample, Vasya may transfer 5 from the first bank to the third.

In the second sample, Vasya may first transfer 1 from the third bank to the second, and then 1 from the second to the first.

In the third sample, the following sequence provides the optimal answer:

transfer 1 from the first bank to the second bank;
transfer 3 from the second bank to the third;
transfer 6 from the third bank to the fourth.

题意:有n个人围成一圈,每个人有a[i]元(可能为负),每次操作可以在相邻的两人间交换任意数目的钱。问最少需要多少次使得所有人的钱数均为0。保证a[]的和为0。

思路:首先是成环的,这意味着若[L, R]区间的和为0, 那么总是可以用R - L次操作使得[L, R]里面所有人的钱变成0。假设有k段满足区间和为0,记长度为len[i](1 <= i <= k),那么结果就是n - k(n = len[1] + … + len[k])。我们只需要最大化k就可以了(就是把无关紧要的0元素记为单独的一块,而其他连续和为0的块尽可能拆开将长度变小)。记录前缀和sum[i],发现若sum[i] == sum[j] 则[i+1, j]区间和是0,同理直到最后一个k满足sum[i] = sum[k],那么[k+1, n] + [1, i]区间和也是0。这样的话,只需要统计出现次数最多的前缀和即可。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 2 * 1e9 + 10;
map<LL, int> fp;
int main()
{
    int n;
    while(scanf("%d", &n) != EOF) {
        int ans = n; fp.clear();
        LL sum = 0;
        for(int i = 1; i <= n; i++) {
            int v; scanf("%d", &v);
            sum += v;
            fp[sum]++;
            ans = min(ans, n - fp[sum]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

题目链接:Codeforces 675D Tree Construction

D. Tree Construction
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
During the programming classes Vasya was assigned a difficult problem. However, he doesn’t know how to code and was unable to find the solution in the Internet, so he asks you to help.

You are given a sequence a, consisting of n distinct integers, that is used to construct the binary search tree. Below is the formal description of the construction process.

First element a1 becomes the root of the tree.
Elements a2, a3, …, an are added one by one. To add element ai one needs to traverse the tree starting from the root and using the following rules:
The pointer to the current node is set to the root.
If ai is greater than the value in the current node, then its right child becomes the current node. Otherwise, the left child of the current node becomes the new current node.
If at some point there is no required child, the new node is created, it is assigned value ai and becomes the corresponding child of the current node.
Input
The first line of the input contains a single integer n (2 ≤ n ≤ 100 000) — the length of the sequence a.

The second line contains n distinct integers ai (1 ≤ ai ≤ 109) — the sequence a itself.

Output
Output n - 1 integers. For all i > 1 print the value written in the node that is the parent of the node with value ai in it.

Examples
input
3
1 2 3
output
1 2
input
5
4 2 3 1 6
output
4 2 2 4
Note
Picture below represents the tree obtained in the first sample.
这里写图片描述

Picture below represents the tree obtained in the second sample.
这里写图片描述

题意:给定n个点的价值a[],让你构造出一棵树。
规定
(1) 第一个节点是root;
(2) 处理第i个节点,从now = root开始,若a[i] > a[now],则查找now的右孩子,反之查找now的左孩子;
(3) 若now不存在,则接上i;
问你最后2 - n的父亲节点的价值;

思路:二叉树,每个点k要么是左孩子、要么是右孩子;
我们可以先找到第一个大于k点价值的节点p,则k一定在p的子树上。
假设p没有左孩子,那么k一定是p的左孩子;反之k一定是p的子树上价值第二大的节点的右孩子。
我们标记每个点是否有左孩子,然后用个set保存所有的值,每次二分一下就好了。

注意:小于set所有值 以及 大于set所有值的情况。

AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 2 * 1e9 + 10;
set<int> son;
set<int> :: iterator it;
map<int, bool> vis;
int a[MAXN];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF) {
        son.clear(); vis.clear();
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        son.insert(a[1]);
        for(int i = 2; i <= n; i++) {
            if(i > 2) printf(" ");
            it = son.lower_bound(a[i]);
            int ans;
            if(it == son.end()) {
                ans = *--it;
            }
            else if(it == son.begin() || vis[*it] == false) {
                ans = *it;
                vis[ans] = true;
            }
            else {
                ans = *--it;
            }
            printf("%d", ans);
            son.insert(a[i]);
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值