常州大学新生寒假训练会试 大佬的生日大礼包

版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/83279205

现在做新生题都很艰难了,为啥其他人都觉得很水,给跪了。

考虑给定3种元素个数 a , b , c a,b,c ,如何判断他们能否形成交错排列。
为了分析方便,设 a b c a\ge b\ge c 。首先,将 c c 摆好,那么最优情况下:

(1) c c 之间形成的 c 1 c-1 个间隔可以放置 a , b , a b , a b a , b a b , a b a b a,b,ab,aba,bab,abab
(2)第一个 c c 之前与最后一个 c c 之后可以放置两段 a b ab 构成的交错排列。

也就是说,先在(1)中的区间放置一些可选的排列,使得放满之后剩余的 a , b a,b 数目满足 a b 2 |a-b|\le 2 即可。
可以发现,放置 a b , a b a b ab,abab 之类消耗相同元素个数的方案不是最优的,因为他们并不会使得 a b |a-b| 变化,同时也消耗了更多的元素(我们应当尽可能减少元素的消耗防止在某个区间没有元素可放)。同样的,放置 a b a , b a b aba,bab 也不是最优的。那么最后的方案就很显然了,即先依次放置 a b 2 a-b-2 a a ,接着交替放置 a a b b 即可,容易证明这是一定满足要求的。
故我们可以得到,对于给定元素个数 a , b , c a,b,c ,如果他们能够形成交错排列,则: c a b 1 c\ge a-b-1

回到问题,在二分时我们需要判断:对于给定的 m m ,是否存在 a A , b B , c C a\le A,b\le B,c\le C ,使得 a + b + c = m a+b+c=m 且他们能够形成交错排列。
考虑直接用 A , B , C A,B,C 进行判断:
如果 C A B 1 C\ge A-B-1 ,那么我们将他们形成的交错排列取掉 C m C-m 个前缀元素或者后缀元素即可;
否则,我们将 A A 减掉 A B ( C + 1 ) A-B-(C+1) ,使得其满足要求。容易证明此时是最优的情况。那么如果 A + B + C A + B + C + 1 = 2 ( B + C ) + 1 m A+B+C-A+B+C+1=2(B+C)+1\ge m ,则存在我们需要的交错排列。

二分即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<random>
using namespace std;
//--Container
//--
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
int ar[3];
bool _cl(int m){
    int tr[3]={ar[0]-m,ar[1]-m,ar[2]};
    if(tr[0]<0||tr[1]<0||tr[0]+tr[1]+tr[2]<m)return 0;
    sort(tr,tr+3);
    if(tr[0]>=tr[2]-tr[1]-1)return 1;
    if(tr[0]*2+tr[1]*2+1<m)return 0;
    return 1;
};
 
void cl(){
    int b,e,m,d;scanf("%d %d %d",&ar[0],&ar[1],&ar[2]);
    for(b=0,e=3000000;b<=e;){
        m=(b+e)>>1;
        if(_cl(m))d=m,b=m+1;
        else
            e=m-1;
    }
    printf("%d\n",d);
};
 
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
    int t;scanf("%d",&t);while(t--)cl();
    return 0;
};

猜你喜欢

转载自blog.csdn.net/u012345506/article/details/83279205