p1m2

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6383

百度之星的比赛题目,这道题里面定义了一个稳定数列,数列的定义如下:

1. 数组里面的元素都是非负整数。
2. 数组里面最大的元素跟最小的元素的差值不超过 1

然后输入一个数列,每次采取+1、-2的策略,问在可以达到稳定数列的情况下,最小值的最大值为多少。

可以证明,最后的-2,+1的数组肯定可以变成稳定数组。因为我们每次的操作相当于把两个数的和减一,两次就是每个数-1.(a-2,b+1,    a+1,b-2)。最后肯定可以变成01这样的数组,就是稳定数组。在变化的过程有稳定数组的存在。说明我们就可以求的答案。

这样可以采取二分法去实现,二分枚举。mid左边的进行+1,右边的-2,判断左边的操作次数与右边的操作次数,若是右边的大于等于左边的,说明答案可能存在mid往上的某一个数,反之亦然。代码如下:

 1 //#include<bits/stdc++.h>
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 #define e exp(1)
 8 #define pi acos(-1)
 9 #define mod 1000000007
10 #define inf 0x3f3f3f3f           //0011_1111_0011_1111_0011_1111_0011_1111
11 #define ll long long
12 #define ull unsigned long long
13 #define mem(a,b) memset(a,b,sizeof(a))
14 int gcd(int a,int b){return b?gcd(b,a%b):a;}     //最大公约数
15   //数组肯定可以达到稳定状态,因为+1、-2肯定可以使值减小1,所以到最后变成01串,肯定可以稳定
16 int a[300005];
17 int main()
18 {
19     int T;scanf("%d",&T);
20     while(T--)
21     {
22         int n;scanf("%d",&n);
23         for(int i=0; i<n; i++)
24         {
25             scanf("%d",&a[i]);
26         }
27         sort(a,a+n);
28         int l=0,r=1e8;
29         int ans=0;
30         while(l<=r)
31         {
32             ll x=0,y=0;                     //x记录加一的次数,y记录减二的次数
33             int mid=(l+r)>>1;                //取中点
34             for(int i=0; i<n; i++)           //比中值小的加一,加差值那么多次,比中值大的减二,减差值除以二的次数
35             {                               //在可以稳定的前提小去向中值靠拢
36                 if(mid>a[i])x+=mid-a[i];
37                 if(mid<a[i])y+=(a[i]-mid)/2;
38             }
39             if(x<=y)                    //如果加的次数小于减的次数,说明答案可能存在mid往上的某一个数,反之亦然
40             {
41                 ans=max(ans,mid);
42                 l=mid+1;
43             }
44             else r=mid-1;
45         }
46         printf("%d\n",ans);
47     }
48     return 0;
49 }

 

posted @ 2018-09-06 17:59  琥琥笙威  阅读(156)  评论(0编辑  收藏  举报