【codeforces VK Cup Round 1】BDE题解

B. Group Photo 2 (online mirror version)

time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Many years have passed, and n friends met at a party again. Technologies have leaped forward since the last meeting, cameras with timer appeared and now it is not obligatory for one of the friends to stand with a camera, and, thus, being absent on the photo.

Simply speaking, the process of photographing can be described as follows. Each friend occupies a rectangle of pixels on the photo: the i-th of them in a standing state occupies a wi pixels wide and a hi pixels high rectangle. But also, each person can lie down for the photo, and then he will occupy a hi pixels wide and a wi pixels high rectangle.

The total photo will have size W × H, where W is the total width of all the people rectangles, and H is the maximum of the heights. The friends want to determine what minimum area the group photo can they obtain if no more than n / 2 of them can lie on the ground (it would be strange if more than n / 2 gentlemen lie on the ground together, isn’t it?..)

Help them to achieve this goal.

Input
The first line contains integer n (1 ≤ n ≤ 1000) — the number of friends.

The next n lines have two integers wi, hi (1 ≤ wi, hi ≤ 1000) each, representing the size of the rectangle, corresponding to the i-th friend.

Output
Print a single integer equal to the minimum possible area of the photo containing all friends if no more than n / 2 of them can lie on the ground.

Sample test(s)
input
3
10 1
20 2
30 3
output
180
input
3
3 1
2 2
4 3
output
21
input
1
5 10
output
50

思路题。

1.枚举最高的人是第 i 个,高度为 m

2.扫描剩下的 n 个人,如果有 h>m 的,计数器 cnt ++,表明这个人必须躺下

3.如果 cnt>n/2 ,说明m这个高度一定不能当最高的,返回第一步继续枚举

4.在上述过程中,我们同时求出 w 的和为 now
如果再让一些人躺下,可以使 now 变小,使答案更优。
除了必须要躺下的 cnt ,我们还可以再另 n/2cnt 个人躺下,来优化答案,这些人必须满足的条件为① a[j].hm a[j].wm ,否则 j 这个人就变成最高的了。
我们把 a[j].ha[j].w 加入递增的优先队列,取出前 n/2cnt <0 的加到 now 中就是对答案的优化了。

注意:一开始这个题WA了,因为最高的高度m可能是某个人的w,即让他躺下的高度。。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
int n;
struct data
{
    int w,h;
}a[1005];
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d%d",&a[i].w,&a[i].h);
    int ans=1e9+5;
    for (int i=1;i<=n;i++)
    {
        int m=a[i].h,now=a[i].w,cnt=0;
        for (int j=1;j<=n;j++)
        {
            if (j!=i&&a[j].h>m)
                cnt++;
            if (a[j].h>m&&a[j].w>m)
                cnt=n+5;
        }
        if (cnt<=n/2)
        {
        for (int j=1;j<=n;j++)
            if (j!=i)
            {
                if (a[j].h>m) now+=a[j].h;
                else 
                {
                    now+=a[j].w;
                    if (a[j].w<=m)
                        q.push(a[j].h-a[j].w);
                }
            }
        while (cnt<n/2&&!q.empty())
        {
            int x=q.top();
            if (x>=0) break;
            now+=x;
            q.pop();
            cnt++;
        }
        while (!q.empty())
            q.pop();
        ans=min(ans,m*now);
        }
        m=a[i].w,now=a[i].h,cnt=1;
        for (int j=1;j<=n;j++)
        {
            if (j!=i&&a[j].h>m)
                cnt++;
            if (a[j].h>m&&a[j].w>m)
                cnt=n+5;
        }
        if (cnt>n/2) continue;
        for (int j=1;j<=n;j++)
            if (j!=i)
            {
                if (a[j].h>m) now+=a[j].h;
                else 
                {
                    now+=a[j].w;
                    if (a[j].w<=m)
                        q.push(a[j].h-a[j].w);
                }
            }
        while (cnt<n/2&&!q.empty())
        {
            int x=q.top();
            if (x>=0) break;
            now+=x;
            q.pop();
            cnt++;
        }
        while (!q.empty())
            q.pop();
        ans=min(ans,m*now);
    }
    printf("%d\n",ans);
    return 0;
}

D. Social Network

time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Polycarpus got an internship in one well-known social network. His test task is to count the number of unique users who have visited a social network during the day. Polycarpus was provided with information on all user requests for this time period. For each query, we know its time… and nothing else, because Polycarpus has already accidentally removed the user IDs corresponding to the requests from the database. Thus, it is now impossible to determine whether any two requests are made by the same person or by different people.

But wait, something is still known, because that day a record was achieved — M simultaneous users online! In addition, Polycarpus believes that if a user made a request at second s, then he was online for T seconds after that, that is, at seconds s, s + 1, s + 2, …, s + T - 1. So, the user’s time online can be calculated as the union of time intervals of the form [s, s + T - 1] over all times s of requests from him.

Guided by these thoughts, Polycarpus wants to assign a user ID to each request so that:

the number of different users online did not exceed M at any moment,
at some second the number of distinct users online reached value M,
the total number of users (the number of distinct identifiers) was as much as possible.
Help Polycarpus cope with the test.

Input
The first line contains three integers n, M and T (1 ≤ n, M ≤ 20 000, 1 ≤ T ≤ 86400) — the number of queries, the record number of online users and the time when the user was online after a query was sent. Next n lines contain the times of the queries in the format “hh:mm:ss”, where hh are hours, mm are minutes, ss are seconds. The times of the queries follow in the non-decreasing order, some of them can coincide. It is guaranteed that all the times and even all the segments of type [s, s + T - 1] are within one 24-hour range (from 00:00:00 to 23:59:59).

Output
In the first line print number R — the largest possible number of distinct users. The following n lines should contain the user IDs for requests in the same order in which the requests are given in the input. User IDs must be integers from 1 to R. The requests of the same user must correspond to the same identifiers, the requests of distinct users must correspond to distinct identifiers. If there are multiple solutions, print any of them. If there is no solution, print “No solution” (without the quotes).

Sample test(s)
input
4 2 10
17:05:53
17:05:58
17:06:01
22:39:47
output
3
1
2
2
3
input
1 2 86400
00:00:00
output
No solution
Note
Consider the first sample. The user who sent the first request was online from 17:05:53 to 17:06:02, the user who sent the second request was online from 17:05:58 to 17:06:07, the user who sent the third request, was online from 17:06:01 to 17:06:10. Thus, these IDs cannot belong to three distinct users, because in that case all these users would be online, for example, at 17:06:01. That is impossible, because M = 2. That means that some two of these queries belonged to the same user. One of the correct variants is given in the answer to the sample. For it user 1 was online from 17:05:53 to 17:06:02, user 2 — from 17:05:58 to 17:06:10 (he sent the second and third queries), user 3 — from 22:39:47 to 22:39:56.

In the second sample there is only one query. So, only one user visited the network within the 24-hour period and there couldn’t be two users online on the network simultaneously. (The time the user spent online is the union of time intervals for requests, so users who didn’t send requests could not be online in the network.)

贪心。

当计算到第 i 个时间的时候,已经有 now 个不同的人:
①如果之前能到达这个时间的人数 <M ,我们直接把这个人设为第 now+1 个人即可

②如果之前能到达这个时间的人已经有 M 个了,那么这个人一定不能设为第 now+1 个,这个人应该设为这 M 人中的哪一个最优呢?
最靠后的那一个!
因为不能到达第 i+1 个时间的人必然是最靠前的几个,如果把当前这个人设成靠前的人 k ,那么 k 很有可能就能到达第 i+1 个时间了,对以后不利;所以设成最靠后的人对以后最有利。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#define N 20005
using namespace std;
int a[N],n,M,T,q[N],ans[N];
int main()
{
    cin>>n>>M>>T;
    for (int i=1;i<=n;i++)
    {
        int h,m,s;
        scanf("%d:%d:%d",&h,&m,&s);
        a[i]=h*3600+m*60+s;
    }
    int h=1,t=0,ok=0,now=0;
    for (int i=1;i<=n;i++)
    {
        while (h<t&&q[h]<a[i])
            h++;
        if (t-h+1<M)
        {
            q[++t]=a[i]+T-1;
            ans[i]=++now;
        }
        else
        {
            q[t]=a[i]+T-1;
            ans[i]=now;
        }
        if (t-h+1==M) ok=1;
    }
    if (ok)
    {
        printf("%d\n",now);
        for (int i=1;i<=n;i++)
            printf("%d\n",ans[i]);
    }
    else
        puts("No solution");
    return 0;
}

E. The Art of Dealing with ATM

time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
ATMs of a well-known bank of a small country are arranged so that they can not give any amount of money requested by the user. Due to the limited size of the bill dispenser (the device that is directly giving money from an ATM) and some peculiarities of the ATM structure, you can get at most k bills from it, and the bills may be of at most two distinct denominations.

For example, if a country uses bills with denominations 10, 50, 100, 500, 1000 and 5000 burles, then at k = 20 such ATM can give sums 100 000 burles and 96 000 burles, but it cannot give sums 99 000 and 101 000 burles.

Let’s suppose that the country uses bills of n distinct denominations, and the ATM that you are using has an unlimited number of bills of each type. You know that during the day you will need to withdraw a certain amount of cash q times. You know that when the ATM has multiple ways to give money, it chooses the one which requires the minimum number of bills, or displays an error message if it cannot be done. Determine the result of each of the q of requests for cash withdrawal.

Input
The first line contains two integers n, k (1 ≤ n ≤ 5000, 1 ≤ k ≤ 20).

The next line contains n space-separated integers ai (1 ≤ ai ≤ 107) — the denominations of the bills that are used in the country. Numbers ai follow in the strictly increasing order.

The next line contains integer q (1 ≤ q ≤ 20) — the number of requests for cash withdrawal that you will make.

The next q lines contain numbers xi (1 ≤ xi ≤ 2·108) — the sums of money in burles that you are going to withdraw from the ATM.

Output
For each request for cash withdrawal print on a single line the minimum number of bills it can be done, or print  - 1, if it is impossible to get the corresponding sum.

Sample test(s)
input
6 20
10 50 100 500 1000 5000
8
4200
100000
95000
96000
99000
10100
2015
9950
output
6
20
19
20
-1
3
-1
-1
input
5 2
1 2 3 5 8
8
1
3
5
7
9
11
13
15
output
1
1
1
2
2
2
2
-1

(因为最多只有两种面额,一开始想直接暴力枚举,但还是TLE了)
用一个map: mp[i] 表示得到 i 的钞票最少需要取 mp[i] 次钱,只要枚举每种钞票取 1k 次,不断更新即可。
(注意 mp[0]=0

预处理好之后,对于每一个询问 x ,我们遍历整个 mp[] ,看能否找到 xmp[i] ,根据各自所需的钞票数更新答案即可。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <map>
#define LL long long
using namespace std;
map<LL,int> mp;
map<LL,int>:: iterator it;
int a[5005],n,k,q;
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=k;j++)
            if (mp.count(j*a[i])) mp[j*a[i]]=min(mp[j*a[i]],j);
            else mp[j*a[i]]=j;
    mp[0]=0;
    scanf("%d",&q);
    while (q--)
    {
        int x,ans=k+1;
        scanf("%d",&x);
        for (it=mp.begin();it!=mp.end();it++)
            if (mp.count(x-it->first))
                ans=min(ans,mp[x-it->first]+it->second);
        if (ans>k) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

(这场比赛BDE应该是最简单的三道,全是乱搞题。。)

你可能感兴趣的:(codeforces,贪心,乱搞)