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