北大2018acm暑期课一贪心&二分&分治

01-派

总时间限制: 1000ms 内存限制: 65536kB
描述
我的生日要到了!根据习俗,我需要将一些派分给大家。我有N个不同口味、不同大小的派。有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成;可以是一整个派)。

我的朋友们都特别小气,如果有人拿到更大的一块,就会开始抱怨。因此所有人拿到的派是同样大小的(但不需要是同样形状的),虽然这样有些派会被浪费,但总比搞砸整个派对好。当然,我也要给自己留一块,而这一块也要和其他人的同样大小。

请问我们每个人拿到的派最大是多少?每个派都是一个高为1,半径不等的圆柱体。

输入
第一行包含两个正整数N和F,1 ≤ N, F ≤ 10 000,表示派的数量和朋友的数量。
第二行包含N个1到10000之间的整数,表示每个派的半径。
输出
输出每个人能得到的最大的派的体积,精确到小数点后三位。
样例输入
3 3
4 3 3
样例输出
25.133

题意:要把N个蛋糕分成F+1份,能切开不能拼接。
思路:一个蛋糕可能分成好多块,可能自己切一切就是一块,也可能太小巴拉巴拉巴拉。这时候不知道该大该小用二分答案来调整蛋糕的大小最适合不过了。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 10100
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, f, mx;
int a[N];

bool check(double mid)
{
    ll sum = 0;
    rep(i, 0, n) sum += PI*a[i]*a[i] / mid;
    return sum < f;
}

int main()
{
   // freopen("data.txt", "r", stdin);

    while(~scanf("%d%d", &n, &f)) {
        ++f;
        mx = -1;
        rep(i, 0, n - 1) {
            scanf("%d", &a[i]);
            mx = max(mx, a[i]);
        }

        double l = 0, r = PI * mx * mx, mid;
        while(l + eps < r) {
            mid = l + (r - l) / 2;
            if(check(mid)) r = mid - eps;
            else l = mid + eps;
        }

        printf("%.3lf\n", mid);
    }

    return 0;
}

02-河中跳房子

描述
每年奶牛们都要举办各种特殊版本的跳房子比赛,包括在河里从一个岩石跳到另一个岩石。这项激动人心的活动在一条长长的笔直河道中进行,在起点和离起点L远 (1 ≤ L≤ 1,000,000,000) 的终点处均有一个岩石。在起点和终点之间,有N (0 ≤ N ≤ 50,000) 个岩石,每个岩石与起点的距离分别为Di (0 < Di < L)。

在比赛过程中,奶牛轮流从起点出发,尝试到达终点,每一步只能从一个岩石跳到另一个岩石。当然,实力不济的奶牛是没有办法完成目标的。

农夫约翰为他的奶牛们感到自豪并且年年都观看了这项比赛。但随着时间的推移,看着其他农夫的胆小奶牛们在相距很近的岩石之间缓慢前行,他感到非常厌烦。他计划移走一些岩石,使得从起点到终点的过程中,最短的跳跃距离最长。他可以移走除起点和终点外的至多M (0 ≤ M ≤ N) 个岩石。

请帮助约翰确定移走这些岩石后,最长可能的最短跳跃距离是多少?

输入
第一行包含三个整数L, N, M,相邻两个整数之间用单个空格隔开。
接下来N行,每行一个整数,表示每个岩石与起点的距离。岩石按与起点距离从近到远给出,且不会有两个岩石出现在同一个位置。
输出
一个整数,最长可能的最短跳跃距离。
样例输入
25 5 2
2
11
14
17
21
样例输出
4
提示
在移除位于2和14的两个岩石之后,最短跳跃距离为4(从17到21或从21到25)。

题意:从一排点中移去一些点使得剩下的最短距离最长。
思路:最短最长,二分味道很浓的题。注意要把最后一个点加进去。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 50100
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, m, L;
int a[N];

bool check(int mid){
    int cnt = 0;
    int t = 0;
    rep(i, 1, n) if(a[i] - a[t] > mid) t = i;
    else cnt++;
    return cnt > m;
}

int main()
{
    //freopen("data.txt", "r", stdin);

    a[0] = 0;
    while(~scanf("%d%d%d", &L, &n, &m)) {
        rep(i, 1, n) {
            scanf("%d", &a[i]);
        }
        a[++n] = L;

        int l = 0, r = L, mid;
        while(l <= r) {
            mid = l + (r - l) / 2;
            if(check(mid)) r = mid - 1;
            else l = mid + 1;
        }

        printf("%d\n", l);
    }

    return 0;
}

03-矩形分割

描述
平面上有一个大矩形,其左下角坐标(0,0),右上角坐标(R,R)。大矩形内部包含一些小矩形,小矩形都平行于坐标轴且互不重叠。所有矩形的顶点都是整点。要求画一根平行于y轴的直线x=k(k是整数) ,使得这些小矩形落在直线左边的面积必须大于等于落在右边的面积,且两边面积之差最小。并且,要使得大矩形在直线左边的的面积尽可能大。注意:若直线穿过一个小矩形,将会把它切成两个部分,分属左右两侧。

输入
第一行是整数R,表示大矩形的右上角坐标是(R,R) (1 <= R <= 1,000,000)。
接下来的一行是整数N,表示一共有N个小矩形(0 < N <= 10000)。
再接下来有N 行。每行有4个整数,L,T, W 和 H, 表示有一个小矩形的左上角坐标是(L,T),宽度是W,高度是H (0<=L,T <= R, 0 < W,H <= R). 小矩形不会有位于大矩形之外的部分。
输出
输出整数n,表示答案应该是直线 x=n。 如果必要的话,x=R也可以是答案。
样例输入
1000
2
1 1 2 1
5 1 2 1
样例输出
5

题意:选一个线使得在左边小矩形面积大于等于右边并且左右两边面积差最小的情况下大矩形左边的面积尽量大。
思路:二分。注意的是第一·l <= r - 2·,·l=mid;r=mid·如果两个再靠近就要特判了,如果写成普通的二分那么在靠近的情况下mid是l,check成立的情况下就直接·r=mid-1·,就直接不考虑r了。第二如果答案是切在小矩形的最右边,那么直接答案是大矩形的最右边。第三开long long。Orz。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 10100
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int R, n;
struct rect{
   ll x, y, w, h;
}a[N];

ll check(int mid) {
    ll l = 0, r = 0;
    rep(i, 1, n) {
        if(a[i].x >= mid) r += a[i].w * a[i].h;
        else if(a[i].x + a[i].w <= mid) l += a[i].w * a[i].h;
        else {
            l += a[i].h * (mid - a[i].x);
            r += a[i].h * (a[i].x + a[i].w - mid);
        }
    }
   // cout << l << ' ' <<r << endl;
   //cout << "mid " << mid << endl;
    return l - r;
}

int main()
{
    //freopen("data.txt", "r", stdin);

    while(~scanf("%d%d", &R, &n)) {
        rep(i, 1, n) scanf("%lld%lld%lld%lld", &a[i].x, &a[i].y, &a[i].w, &a[i].h);
        ll maxx = 0;
        rep(i, 1, n) maxx = max(maxx, a[i].x + a[i].w);
        int l = 0, r = R, mid;
        while(l <= r - 2) {
            mid = l + (r - l) / 2;
            if(check(mid) > 0) r = mid;
            else l = mid;
        }

        int ll = check(l), rr = check(r);
        if(abs(ll) >= abs(rr)) mid = r;
        else mid = l;
        if(mid == maxx) mid = R;
        printf("%d\n", mid);
    }

    return 0;
}

04-Gone Fishing

描述
John is going on a fishing trip. He has h hours available (1 <= h <= 16), and there are n lakes in the area (2 <= n <= 25) all reachable along a single, one-way road. John starts at lake 1, but he can finish at any lake he wants. He can only travel from one lake to the next one, but he does not have to stop at any lake unless he wishes to. For each i = 1,…,n - 1, the number of 5-minute intervals it takes to travel from lake i to lake i + 1 is denoted ti (0 < ti <=192). For example, t3 = 4 means that it takes 20 minutes to travel from lake 3 to lake 4. To help plan his fishing trip, John has gathered some information about the lakes. For each lake i, the number of fish expected to be caught in the initial 5 minutes, denoted fi( fi >= 0 ), is known. Each 5 minutes of fishing decreases the number of fish expected to be caught in the next 5-minute interval by a constant rate of di (di >= 0). If the number of fish expected to be caught in an interval is less than or equal to di , there will be no more fish left in the lake in the next interval. To simplify the planning, John assumes that no one else will be fishing at the lakes to affect the number of fish he expects to catch.
Write a program to help John plan his fishing trip to maximize the number of fish expected to be caught. The number of minutes spent at each lake must be a multiple of 5.
输入
You will be given a number of cases in the input. Each case starts with a line containing n. This is followed by a line containing h. Next, there is a line of n integers specifying fi (1 <= i <=n), then a line of n integers di (1 <=i <=n), and finally, a line of n - 1 integers ti (1 <=i <=n - 1). Input is terminated by a case in which n = 0.
输出
For each test case, print the number of minutes spent at each lake, separated by commas, for the plan achieving the maximum number of fish expected to be caught (you should print the entire plan on one line even if it exceeds 80 characters). This is followed by a line containing the number of fish expected.
If multiple plans exist, choose the one that spends as long as possible at lake 1, even if no fish are expected to be caught in some intervals. If there is still a tie, choose the one that spends as long as possible at lake 2, and so on. Insert a blank line between cases.
样例输入
2
1
10 1
2 5
2
4
4
10 15 20 17
0 3 4 3
1 2 3
4
4
10 15 50 30
0 3 4 3
1 2 3
0
样例输出
45, 5
Number of fish expected: 31

240, 0, 0, 0
Number of fish expected: 480

115, 10, 50, 35
Number of fish expected: 724

题意:在湖里选出一些垂钓使得鱼最多。
思路:首先吧,答案肯定和选哪些湖有关,又因为路的原因不一定是湖越肥越好,因为可能太远了(一开始还想把路和湖的参数合起来写成一个权值)。枚举湖的范围的方法是枚举最后一个湖(前面的湖也有可能不用,但是路就确定下来了)。那么在选择1到i的湖的时候的问题就可以贪心做了——选取捞鱼最多的湖捞,哪怕是先捞的后面的湖也可以看做是后来再来的,时间转换一下思维就没问题了。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 50
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, h, f[N], d[N], t[N], ans[N][N], ft[N];
bool flag;
int main()
{
   // freopen("data.txt", "r", stdin);

    while(~scanf("%d%d", &n, &h) && n) {
        if(flag) putchar('\n');
        flag = true;
        h *= 12;
        memset(ans, 0, sizeof ans);

        rep(i, 1, n) scanf("%d", &f[i]);
        rep(i, 1, n) scanf("%d", &d[i]);
        rep(i, 1, n - 1) scanf("%d", &t[i]);

        rep(i, 1, n) {
            rep(j, 1, i) ft[j] = f[j];
            int ht = h;
            rep(j, 1, i - 1) ht -= t[j];
            int k, emp = 0;
            while(ht > 0 && emp + 1 <= i) {
                k = emp + 1;
                rep(j, emp + 1, i) if(ft[j] > ft[k]) k = j;
                ans[i][0] += ft[k];
                ++ans[i][k];
                --ht;
                ft[k] -= d[k];
                if(ft[k] < 0) ft[k] = 0;
                rep(j, emp + 1, i) if(!ft[j]) emp++; else break;
            }
            if(ht > 0) ans[i][1] += ht;
        }
        int a = 1;
       // rep(i, 1, n) cout << ans[i][0] << endl;
        rep(i, 2, n) if(ans[i][0] > ans[a][0]) a = i;
        rep(i, 1, n) {
            printf("%d", ans[a][i] * 5);
            if(i < n) printf(", ");
        }
        printf("\nNumber of fish expected: %d\n", ans[a][0]);
    }

    return 0;
}

05-Tian Ji – The Horse Racing

描述
Here is a famous story in Chinese history.
That was about 2300 years ago. General Tian Ji was a high official in the country Qi. He likes to play horse racing with the king and others.

Both of Tian and the king have three horses in different classes, namely, regular, plus, and super. The rule is to have three rounds in a match; each of the horses must be used in one round. The winner of a single round takes two hundred silver dollars from the loser.

Being the most powerful man in the country, the king has so nice horses that in each class his horse is better than Tian’s. As a result, each time the king takes six hundred silver dollars from Tian.

Tian Ji was not happy about that, until he met Sun Bin, one of the most famous generals in Chinese history. Using a little trick due to Sun, Tian Ji brought home two hundred silver dollars and such a grace in the next match.

It was a rather simple trick. Using his regular class horse race against the super class from the king, they will certainly lose that round. But then his plus beat the king’s regular, and his super beat the king’s plus. What a simple trick. And how do you think of Tian Ji, the high ranked official in China?

Were Tian Ji lives in nowadays, he will certainly laugh at himself. Even more, were he sitting in the ACM contest right now, he may discover that the horse racing problem can be simply viewed as finding the maximum matching in a bipartite graph. Draw Tian’s horses on one side, and the king’s horses on the other. Whenever one of Tian’s horses can beat one from the king, we draw an edge between them, meaning we wish to establish this pair. Then, the problem of winning as many rounds as possible is just to find the maximum matching in this graph. If there are ties, the problem becomes more complicated, he needs to assign weights 0, 1, or -1 to all the possible edges, and find a maximum weighted perfect matching…

However, the horse racing problem is a very special case of bipartite matching. The graph is decided by the speed of the horses – a vertex of higher speed always beat a vertex of lower speed. In this case, the weighted bipartite matching algorithm is a too advanced tool to deal with the problem.

In this problem, you are asked to write a program to solve this special case of matching problem.
输入
The input consists of up to 50 test cases. Each case starts with a positive integer n ( n<=1000) on the first line, which is the number of horses on each side. The next n integers on the second line are the speeds of Tian’s horses. Then the next n integers on the third line are the speeds of the king’s horses. The input ends with a line that has a single `0’ after the last test case.
输出
For each input case, output a line containing a single number, which is the maximum money Tian Ji will get, in silver dollars.
样例输入
3
92 83 71
95 87 74
2
20 20
20 20
2
20 19
22 18
0
样例输出
200
0
0

题意:两帮马比赛,赢了奖励输了罚款,平局没事。
思路:本来我想的是比较最好的马,如果tian比不过就拿最坏的马来拖king的宝马下水。然后又想还可能平啊,还可能连续平,,,百度下来才知道要两段一起比,最好的马和最渣渣的马都是等价的不正常马,能赢就赢,如果不能赢的话再看。然后能用渣渣换宝马就换,不亏不亏。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1010
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, a[N], b[N], ans;

int main()
{
   // freopen("data.txt", "r", stdin);

    while(~scanf("%d", &n) && n) {
        rep(i, 0, n - 1) scanf("%d", &a[i]);
        rep(i, 0, n - 1) scanf("%d", &b[i]);
        sort(a, a + n, greater<int>());
        sort(b, b + n, greater<int>());
        ans = 0;
        int i = 0, j = 0, k = n - 1, l = n - 1;
        while(i <= k && j <= l) {
            if(a[i] > b[j]) {
                ans++; i++; j++;
            }
            else if(a[k] > b[l]) {
                ans++; k--; l--;
            }
            else {
                if(a[k] < b[j]) ans--;
                k--;
                j++;
            }
        }

        //cout << ans << ' ' << e << endl;
        printf("%d\n", ans * 200);
    }

    return 0;
}

06:Radar Installation

描述
Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.

We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.

Figure A Sample Input of Radar Installations
输入
The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.

The input is terminated by a line containing pair of zeros
输出
For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. “-1” installation means no solution for that case.
样例输入
3 2
1 2
-3 1
2 1

1 2
0 2

0 0
样例输出
Case 1: 2
Case 2: 1

题意:放最少的雷达覆盖所有岛屿。
思路:这题是真的吓人,先要建模成线段覆盖,然后贪心的思路也不是很好想,还需要证明个结论。还好老师讲了,需要维护一个前面未被覆盖区间的最左边的右边界。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 20100
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct node {
  double s, e;
  node(double ss = 0.0, double ee = 0.0):s(ss), e(ee){}
  bool operator < (const node & b) const{
      if(fabs(s - b.s) <= eps){
        return e < b.e;
      }
      return s < b.s;
  }
};

node l[N];

int n, d, x, y, ans;

int main()
{
   // freopen("data.txt", "r", stdin);

    int cse = 0;
    while(scanf("%d%d", &n, &d) && n + d) {
        bool flag = true;
        //cout << n << ' ' << d << endl;
        rep(i, 0, n - 1) {
            scanf("%d%d", &x, &y);
            if(y > d) {
                flag = false;
            }
            double dis = sqrt(1.0*d*d - 1.0*y*y);
            l[i].s = x - dis; l[i].e = x + dis;
           // cout << i << endl;
        }
        if(!flag) {
            printf("Case %d: -1\n", ++cse); continue;
        }
        sort(l, l + n);
        double f = -INF;
        ans = 0;
        rep(i, 0, n - 1) {
            if(l[i].s > f) {
                f = l[i].e;
                ans++;
            }
            else if(f > l[i].e){
                f = l[i].e;
            }
        }
        printf("Case %d: %d\n", ++cse, ans);
    }

    return 0;
}

07-求排列的逆序数

忘了归并排序怎么写了,还是百度的。

08-输出前k大的数

这数据直接sort,懒得写分治那种。

这些题目都挺考验基本功的,对于我这种半路出家不怎么熟悉知识体系的人真是太有用了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值