2017暑期ACM俱乐部个人训练赛第4场 G题和J题



问题 G: Paired Up

时间限制: 1 Sec   内存限制: 128 MB

题目描述

Farmer John finds that his cows are each easier to milk when they have another cow nearby for moral support. He therefore wants to take his M cows (M1,000,000,000, M even) and partition them into M/2 pairs. Each pair of cows will then be ushered off to a separate stall in the barn for milking. The milking in each of these M/2 stalls will take place simultaneously. 
To make matters a bit complicated, each of Farmer John's cows has a different milk output. If cows of milk outputs A and are paired up, then it takes a total of A+B units of time to milk them both.

Please help Farmer John determine the minimum possible amount of time the entire milking process will take to complete, assuming he pairs the cows up in the best possible way.

输入

The first line of input contains  N  ( 1N100,000 ). Each of the next  N  lines contains two integers  x  and  y , indicating that FJ has  x  cows each with milk output  y  ( 1y1,000,000,000 ). The sum of the  x 's is  M , the total number of cows.

输出

Print out the minimum amount of time it takes FJ's cows to be milked, assuming they are optimally paired up.

样例输入

3

1 8

2 5

1 2

样例输出

10

提示

Here, if the cows with outputs 8+2 are paired up, and those with outputs 5+5 are paired up, the both stalls take 10 units of time for milking. Since milking takes place simultaneously, the entire process would therefore complete after 10 units of time. Any other pairing would be sub-optimal, resulting in a stall taking more than 10 units of time to milk.





题目大意:
John有M头牛    他发现两头牛在一起挤奶会挤出更多的奶     所以他就把M头牛分成 M/2 组进行挤奶     他又发现如果牛1产奶量是A  牛2产奶量是B   那么这两头牛在一起挤奶就会耗时  A+B    他想知道怎么分组才能使所有牛都完成挤奶耗时最短(每组同时进行)   求最短时间       

分析:
数据量给的是相当大   直接开数组是不可能的了    还好用结构体表示一下就好了     思路还是很简单的直接模拟一下     先排序   然后取两头求和    取最大   就是完成所需的最短时间   




AC代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
struct node {
    ll x;//         奶牛数量
    ll y;//         产奶量(时间)
}a[100010];
int cmp(node c,node d){
    return c.y>d.y;
}
int main(){
    int n;
    //freopen("data","r",stdin);
    while (scanf ("%d",&n)!=EOF){
        ll maxn=-1;
        for (int i=0;i<n;i++){
            scanf ("%lld%lld",&a[i].x,&a[i].y);
        }
        sort(a,a+n,cmp);
        int i=0;
        int j=n-1;
        ll l,r;
        while (i<j){
            if(a[i].x){
                l=a[i].y;
            }
            else{
                i++;
                l=a[i].y;
            }
            if(a[j].x){
                r=a[j].y;
            }
            else{
                j--;
                r=a[j].y;
            }
            if(a[j].x>a[i].x){//             进行优化   将左右两端和相同的跳过
                a[j].x-=a[i].x;
                a[i].x=0;
            }
            else{
                a[i].x-=a[j].x;
                a[j].x=0;
            }
            if(maxn<l+r)
                maxn=l+r;
        }
        printf ("%lld\n",maxn);
    }
    return 0;
}








问题 J: 【排序】奶牛的编号

时间限制: 1 Sec   内存限制: 64 MB

题目描述

有N(1≤N≤1000)头奶牛,它们都被标上一个优先等级编号:1,2或3。用来表示它们喝水时的优先次序,编号为l的最优先,编号为2的其次,编号为3的最后。每天奶牛开始时排成一行,但总是很乱,需要你把它们重新排成编号为1的奶牛在最前面,编号为2的其次,编号为3的奶牛在最后。你能计算出最少需要多少的交换次序来完成这次重排吗?

输入

第1行:1个整数N;
第2至N+I行:第i+l行有一个整数表示开始队列中第i头奶牛的编号。

输出

1行,只一个整数,表示最少需要交换次数。

样例输入

9

2

2

1

3

3

3

2

3

1

样例输出

4

提示

样例说明:有一种交换方法。
2 2 2< 1 1
2< 1 1 1 1
1< 2 2 2 2
3 3< 2 2 2
3 3 3 3< 2
3 3 3 3 3
2 2< 3 3 3
3 3 3 3 3
1 1 1< 2< 3




分析:
提示是真心没看懂   欢迎评论提示解读   其实如果没有相同的数字可以先求一下数列的最长递增子序列然后用序列长度减去最长递增子序列就能得到结果   然而有相同数字就不行了    
思路:先将数列进行排序     与给定数列对比      若给定数列中数字和排序后位置相同的即不需要交换    若不同
首先    该数字 b[i] 在原序列的位置为 i      在排序后位置为 i 的数字为a[i]       找到排序后的数列中 b[i]   所在位置   j     对应于原序列  位置 j   的数字  b[j]    若 a[i]==b[j]     则只需进行一次交换    就可以将原数列中的数字归位     扫一遍原数列   将能交换的交换    剩下不能一次 完成 交换的     三个数字一组   交换两次即可




AC代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[1010];
int b[1010];
int main (){
    int n;
    //freopen("data","r",stdin);
    while(scanf("%d",&n)!=EOF){
        memset(a,0,sizeof(b));
        memset(b,0,sizeof(b));
        for (int i=0;i<n;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(a,a+n);
        int sum=0;
        for (int i=0;i<n;i++)
            if(a[i]==b[i])
                b[i]=-1;
        for (int i=0;i<n;i++){
            if(b[i]!=-1){
                int temp=b[i];
                for (int j=i;j<n;j++){
                    if(a[j]!=-1){
                        if(a[j]==temp){
                            if(b[j]==a[i]){
                                sum++;
                                b[i]=-1;
                                b[j]=-1;
                                break;
                            }
                        }

                    }
                }
            }
        }
        int sum2=0;
        for (int i=0;i<n;i++){
            if(b[i]!=-1)
                sum2++;
        }
        printf ("%d\n",sum2-sum2/3+sum);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值