HDU1205 鸽巢原理/找规律


1)

利用鸽巢原理,很简单做。

让所有相同种类的糖果分开,我们让最大数目的糖果作为挡板,放在其他糖果间。而为了让最大数目的糖果自己不会连续出现,所以确保每一个之间一定要有别的糖果,所以求得其他糖果数量之和,如果和大于等于(最大数目的糖果数目-1),问题就会得到解决。不用担心其他糖果会连续出现,如果有一种糖果连续出现,那么这种糖果的数量一定大于最大糖果,与假设不符,遂不成立。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <vector>

using namespace std;

long long int sum=0;
int flag=0;
int main()
{
    int t; scanf("%d",&t);
    while(t--){

        int n; scanf("%d",&n);
        int num;
        flag=0;
        sum=0;
        int maxx=0;
        for(int l=1;l<=n;l++){
            scanf("%d",&num);
            maxx=max(maxx,num);
            sum+=num;
        }
        sum-=maxx;
        //cout<<sum<<endl;
        //cout<<maxx<<endl;
        if(maxx-1<=sum){
            flag=1;
        }
        if(flag){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }

    }
    return 0;
}



2)自己找规律做

Code:用栈或者数组模拟栈,如果两个糖果的数目相同,则用sum记录两个糖果数量之和略过,继续读数,读完以后将没有用sum记录的糖果的数目按大小压入栈,将最大的数和第二大的数不断减1,直到第二大的数等于第三大的数,然后将相同的两个数出栈(用sum+=两数之和),直到除了最大的数以外,其他所有数是两两相等,那么sum>=(此时最大数的值-1)就判定为Yes.

思想:两个糖果数目相等,则这两个糖果最后一定可以互相搭配的被吃完,而且可以在两个糖果中间放别的糖果,所以起到两重作用。Code中记录sum,以及相等就忽略/出栈,就起到了这两个作用。

注意:用到的变量要及时清零,注意特殊情况比如没有数入栈则直接判定为Yes,等。

(刚开始想用set存储,但因为set内元素不能被更改,只能删除以后再插入效率低,所以舍弃;队列再插入时就会插入到队尾(后放入的)而不是队首(先放入的)所以也舍弃。于是用栈,WA,以为超出栈的范围,于是数组模拟栈,后来发现是没有及时sum=0的原因,两者都能过。)

①栈

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>

using namespace std;
int matrix[1000010];
long long int sum=0;
int flag=0;
int main()
{
    int t; scanf("%d",&t);
    while(t--){
        memset(matrix,0,sizeof(matrix));
        sum=0;
        int n; scanf("%d",&n);
        int num;
        flag=0;
        for(int l=1;l<=n;l++){
            scanf("%d",&num);
            matrix[num]++;
            if(matrix[num]==2) {matrix[num]=0;sum+=(num*2);}
        }
        stack <int> qq;
        qq.push(0);
        for(int l=1;l<=1000000;l++){//for(;l<=1000010;),因为l==1000010越界了,所以输出了
            if(matrix[l]!=0){
                qq.push(l);
            }
        }

        int l3=-1,l2=-1,l1=-1;
        if(qq.size()==1){
            cout<<"Yes"<<endl;
            continue;
        }
        while(qq.size()>=3){
            l3=qq.top();qq.pop();
            l2=qq.top();qq.pop();
            l1=qq.top();qq.pop();
            l3-=(l2-l1);
            sum+=(l1*2);
            qq.push(l3);
        }
        l3=qq.top();
        if(sum>=(l3-1)){
            flag=1;
        }
        if(flag){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }

    }
    return 0;
}
②数组模拟栈:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <vector>

using namespace std;
int matrix[1000010];
int stackk[1000010];
long long int sum=0;
int flag=0;
int main()
{
    int t; scanf("%d",&t);
    while(t--){
        memset(matrix,0,sizeof(matrix));
        memset(stackk,0,sizeof(stackk));
        sum=0;
        int n; scanf("%d",&n);
        int num;
        flag=0;
        for(int l=1;l<=n;l++){
            scanf("%d",&num);
            matrix[num]++;
            if(matrix[num]==2) {matrix[num]=0;sum+=(num*2);}
        }
        stackk[0]=0;
        int top=0;
        for(int l=1;l<=1000000;l++){
            if(matrix[l]!=0){
                stackk[++top]=l;
            }
        }
        if(top==0){
            cout<<"Yes"<<endl;
            continue;
        }
        int l3=-1,l2=-1,l1=-1;
        int l;
        for(l=top;l>=2;l=l-2){
            l3=stackk[l];
            l2=stackk[l-1];
            l1=stackk[l-2];
            l3-=(l2-l1);
            sum+=(l1*2);
            stackk[l-2]=l3;
        }
        l3=stackk[l];
        if(sum>=(l3-1)){
            flag=1;
        }
        if(flag){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }

    }
    return 0;
}
③参考 别人的,直接找出规律,比我写的更接近问题本质

/*如果最大堆-次大堆<=1,那么问题肯定有解:
我们可以从最大和次大里面每次拿一个,然后等他们和第三大堆相等的时候
,每次从三堆里面各拿一个,等他们和第四大堆相等的时候
,每次从四堆里面各拿一个,这样一直拿完所有堆。
问题变成了能不能使得最大堆-次大堆<=1,所以之前我们会从次大堆之外的那些堆里面取,
来让最大堆减少,如果能减到:最大堆-次大堆<=1,那么原问题有解。
能否减到要看:
sum - max - max2 >= max - max2 - 1
是否成立,其中sum为总和,max为最大堆,max2为次大。
整理得:
2 * max - sum <= 1
*/
#include<stdio.h>
int main()
{
    int cas,n,max;
    scanf("%d",&cas);
    while(cas--)
    {
        __int64 sum;
        sum=max=0;
        scanf("%d",&n);
        while(n--)
        {
            int num;
            scanf("%d",&num);
            if(max<num) max=num;
            sum+=num;
        }
        if(2*max-sum<=1) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值