卡牌分组([AtCoder ARC073]Ball Coloring)

1. 题目描述:
前两道题说了东东和东东爸过去的故事, 现在我们就预测东东未来几年在小学的生活。
小东东上小学时也许会喜欢一种玩具——卡牌。 这里为了出这道题就设每张卡牌只有一个非负整数属性值。 有一天, 小东东买了N包卡牌,每包里有两张卡牌( 设有一张卡片的属性值是xi,另一张的属性值是yi) (就是说小东东一共买了2N张卡牌) 。 小东东要把每包里的两张卡牌都分开,并分别放到左右两堆(如果认为描述不清楚请仔细食用样例) 。
小东东定义了以下的一些数值:
Lmax:放在小东东左边卡牌堆里的卡牌中属性值最大的卡牌的属性值

 

2. 输入:
第一行一个整数N表示小东东买了N包卡牌。
接下来有N行,每行包含两个正整数xi, yi表示第i行的两张卡牌的属性值。


3. 输出:
一个整数表示最小的(Rmax − Rmin)×(Lmax − Lmin)。

Lmin:放在小东东左边卡牌堆里的卡牌中属性值最小的卡牌的属性值
Rmax:放在小东东右边卡牌堆里的卡牌中属性值最大的卡牌的属性值
Rmin:放在小东东右边卡牌堆里的卡牌中属性值最小的卡牌的属性值
小东东肯定想知道可以算出的最小的(Rmax − Rmin)×(Lmax − Lmin)。 但是小东东要玩耍,所以就把这个有趣的任务交给了你。

 

 

分类讨论;

答案由四个变量构成,而对于一组数据,一定有MAX_W,MIN_W(所有属性值中最大、最小值)分别是定值;

而Lmax(或Rmax)=MAX_W,Lmin(或Rmin)=MIN_W;

所以有两种情况:

  ①MAX_W与MIN_N在不同侧:(假设MAX在左,MIN在右)

    这种情况十分容易处理。左堆上边界固定,右堆下边界固定,因此这种情况下只需要让左堆的值尽量大,右堆的值尽量小;

    即对于任意一对属性值,较大值放在左堆,较小值放在右堆,结束;

  ②MAX_W与MAX_N在同侧:(假设MAX与MIN同在左)

    这种情况处理方式较为繁琐。左堆上下边界固定,因此只需计算 Rmax-Rmin 的最小值;

    关于枚举方式,首先把属性值大值放左堆,小值放右堆(同①),然后根据右堆属性值由小到大排序(当然反过来也可以);

    然后从上到下依次交换左右属性值(交换第一次时MIN_W被换到了左堆);

    关于正确性,排序之后,任意一个左堆属性值Lw[a]一定大于右堆中下标<=a的值;

    即交换后不会导致Rmin减小,但有可能使Rmax和Rmin增大,但对于上一组Rmax与Rmin对应的ans已经计算过了,因此不会对答案造成影响;

  注:MAX_W与MIN_W在同一组时只出现①情况;

AC GET☆DAZE

 

↓代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #define ll long long
  7 #define MAX_N 1000000039
  8 using namespace std;
  9 struct card
 10 {
 11     ll lw,rw;
 12 };
 13 card num[200039];
 14 ll lmax=-1,rmax=-1,lmin=MAX_N,rmin=MAX_N,rankmax,rankmin,smax,smin=MAX_N,stpmin=MAX_N;
 15 bool cmp(card a,card b)
 16 {
 17     return a.rw<b.rw;
 18 }
 19 void exc(int k)
 20 {
 21     int stp;
 22     stp=num[k].rw;
 23     num[k].rw=num[k].lw;
 24     num[k].lw=stp;
 25 }
 26 int main()
 27 {
 28     ll ans,stp,stpans,n,a,b,c;
 29     scanf("%lld",&n);
 30     for(a=1;a<=n;a++)
 31     {
 32         scanf("%lld%lld",&b,&c);
 33         num[a].lw=max(b,c);
 34         num[a].rw=min(b,c);
 35         if(num[a].lw>=lmax)
 36         {
 37             lmax=num[a].lw;
 38             rankmax=a;
 39         }
 40         if(num[a].rw<=rmin)
 41         {
 42             rmin=num[a].rw;
 43             rankmin=a;
 44         }
 45         lmin=min(lmin,num[a].lw);
 46         rmax=max(rmax,num[a].rw);
 47     }
 48     ans=(lmax-lmin)*(rmax-rmin);
 49     stp=lmax-rmin;
 50     if(rankmax!=rankmin)
 51     {
 52         sort(num+1,num+1+n,cmp);
 53         for(a=1;a<=n;a++)
 54         {
 55             if(num[a].lw==lmax)
 56             {
 57                 rankmax=a;
 58                 break;
 59             }
 60         }
 61         exc(1);
 62         if(num[1].rw<=num[2].rw)
 63         {
 64             smin=num[1].rw;
 65             rankmin=1;
 66         }
 67         else   
 68         {
 69             smin=num[2].rw;
 70             rankmin=2;
 71         }
 72         smax=max(num[1].rw,num[n].rw);
 73         ans=min(ans,stp*(smax-smin));
 74         for(a=2;a<=n;a++)
 75         {
 76             if(a!=rankmax)
 77             {
 78                 exc(a);
 79             }
 80             if(a==rankmin)
 81             {
 82                 if(num[a].rw>num[a+1].rw)
 83                 {
 84                     smin=num[a+1].rw;
 85                     rankmin=a+1;
 86                 }
 87                 else
 88                 {
 89                     smin=num[a].rw;
 90                     rankmin=a;
 91                 }
 92             }
 93             stpmin=min(stpmin,num[a-1].rw);
 94             if(stpmin<=smin)
 95             {
 96                 smin=stpmin;
 97                 rankmin=1;
 98             }
 99             smax=max(smax,num[a].rw);
100             ans=min(ans,stp*(smax-smin));
101         }
102     }
103     printf("%lld",ans);
104     return 0;
105 }
View Code
散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ
原文地址:https://www.cnblogs.com/Sinogi/p/7066794.html