HDU1205 鸽巢原理/找规律

原创 2016年05月30日 20:17:27


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;
}







版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

hdu 1205 吃糖果(鸽巢原理)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1205 Problem Description HOHO,终于从Speakless手上赢走了...

hdu 1205 有意思的小题 2种解法 鸽巢原理

吃糖果 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Subm...

鸽巢原理 Poj3370&Hdu1808 + Poj2356 + Hdu 1205

2014-3-25 更新 :修正了Hdu1205的代码,貌似以前的版本过不了,少输出了回车。 Poj 的一个评论很有启发:http://poj.org/showmessage?message_id=...

HDU-3183——A Magic Lamp(RMQ问题+鸽巢原理)

题意:给你一个共n位的数,让你删除其中的m个位,而且不改变原来数位的顺序,使得余下的数位组成的数最小! 分析:大多数人看到标题上的鸽巢原理肯定会疑惑,鸽巢原理是什么屌定理!然后仔细一看必然大失所望,原...

HDU 1808.Halloween treats【鸽巢原理】【11月25】

alloween treats Problem Description Every year there is the same problem at Halloween: Each ...

[HDU 1664] Different Digits DFS+鸽巢原理

给你一个数,要你找它的一个倍数,但是要求倍数里面出现的数字最少,比如15的倍数出现两个数字的是15,一个数字的是555,所以结果是555。...

HDU 1029(鸽巢原理)

Ignatius and the Princess IV Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32767 K ...

HDU3183(RMQ+鸽巢原理)

题目的意思是对于一个n位数,删除m个位后,得到的最小数是什么,比如12345 2,删除两个位,得到最小的就是123.实际上这题目解法很多,好像有贪心,线段树,RMQ等,因为我最近在学习RMQ,所以就用...

基于JAVA的鸽巢原理

  • 2015年01月05日 17:22
  • 30KB
  • 下载

组合数学 第二章 鸽巢原理

  • 2015年06月14日 21:32
  • 3.96MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU1205 鸽巢原理/找规律
举报原因:
原因补充:

(最多只允许输入30个字)