HDU 5353—— Average——————【贪心+枚举】

Average

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2069    Accepted Submission(s): 517
Special Judge

Problem Description

There are n soda sitting around a round table. soda are numbered from 1 to n and i-th soda is adjacent to (i+1)-th soda, 1-st soda is adjacent to n-th soda.

Each soda has some candies in their hand. And they want to make the number of candies the same by doing some taking and giving operations. More specifically, every two adjacent soda x and y can do one of the following operations only once:
1. x-th soda gives y-th soda a candy if he has one;
2. y-th soda gives x-th soda a candy if he has one;
3. they just do nothing.

Now you are to determine whether it is possible and give a sequence of operations.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first contains an integer n (1≤n≤105), the number of soda.
The next line contains n integers a1,a2,…,an (0≤ai≤109), where ai denotes the candy i-th soda has.

Output

For each test case, output "YES" (without the quotes) if possible, otherwise output "NO" (without the quotes) in the first line. If possible, then the output an integer m(0≤m≤n) in the second line denoting the number of operations needed. Then each of the following m lines contain two integers x and y (1≤x,y≤n), which means that x-th soda gives y-th soda a candy.

Sample Input

3

6

1 0 1 0 0 0

5

1 1 1 1 1

3

1 2 3

Sample Output

NO

YES

0

YES

2

2 1

3 2

题目大意:有n个人围成一圈,每个人手上都有一定数量的糖果,相邻两个人可是给一个糖果,但是只能给一次,如x,y。x可以给y一个糖果,或者y可以给x一个糖果。也可以不操作,即都不给糖果。第一个人可以给第n个人一个糖果,或者第n个人给第一个人一个糖果,或不给。问是否可以通过给糖果这样的操作,让所有的人手中的糖果数量相同。如果可以,输出YES和需要多少次,同时输出路径。否则输出NO。

解题思路:枚举第一个人对第二个人的三种操作,然后看第二个人跟average的差值,如果是-1,那么第二个人从第三个人手中拿走一个糖果,如果是1,那么第二个人给第三个人一个糖果,如果为零,则不操作。依次遍历到n。因为第n个人跟第1个人是可以操作的,所以我在操作第n个的时候,把对第一个人的操作放在了n+1的位置,c[1]+=c[n+1]判断第一个人的结果是否为零,如果为零,这说明可以,否则不可以。

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=1e5+200;
typedef long long INT;
int a[maxn] ,b[maxn] ,c[maxn];
int f[3]={0,1,-1};
int abs(int x){
    return x>0? x: -x;
}
struct Oper{
    int x,y;
}oper[maxn];
int main(){

    int t,n;
    scanf("%d",&t);
    while(t--){

        scanf("%d",&n);
        INT sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        if(sum%n!=0){
            printf("NO\n");continue;
        }else{
            if(n==1){   //1个的时候必然YES
                printf("YES\n0\n");
                continue;
            }
            if(n==2){       //特判两个的情况
                if(a[1]-a[2]==2){
                    printf("YES\n1\n");
                    printf("1 2\n"); continue;
                }else if(a[1]-a[2]==-2){
                    printf("YES\n1\n");
                    printf("2 1\n");continue;
                }else if(a[1]==a[2]){
                    printf("YES\n");
                    printf("0\n");continue;
                }
            }
            const int ave=sum/n;
            int flag=0;
            for(int i=1;i<=n;i++){
                b[i]=a[i]-ave;  //把跟平均数的差值放在b数组中
                if(abs(b[i])>2){
                    printf("NO\n");
                    flag=1;
                    break;
                }
            }
            if(flag)
                continue;
            int num;
            b[n+1]=0;
            for(int k=0;k<3;k++){
                num=0;  //num放错位置,wa了
                for(int i=1;i<=n+1;i++){
                    c[i]=b[i];
                }
                if(f[k]==1){
                    oper[num].x=2;
                    oper[num++].y=1;
                }else if(f[k]== -1){
                    oper[num].x=1;
                    oper[num++].y=2;
                }
                //每次对c数组操作
                c[1]+=f[k];
                if(abs(c[1])>1 ){
                    continue;
                }
                c[2]-=f[k];
                if(abs(c[2])>1){
                    continue;
                }
                int mark=0;
                for(int i=2;i<=n;i++){  //遍历2-->n
                    if(c[i]==1){
                        c[i]-=1;
                        c[i+1]+=1;
                        if(i<n){
                            oper[num].x=i;
                            oper[num++].y=i+1;
                        }else{
                            oper[num].x=n;
                            oper[num++].y=1;
                        }

                    }else if(c[i]==-1){
                        c[i]+=1;
                        c[i+1]-=1;
                        if(i<n){
                            oper[num].x=i+1;
                            oper[num++].y=i;
                        }else{
                            oper[num].x=1;
                            oper[num++].y=n;
                        }
                    }
                    else if(abs(c[i])>1){
                        mark=1;
                        break;
                    }
                }
                if(mark){
                    continue;
                }
                if(c[1]+c[n+1]!=0){
                    continue;
                }else{
                    flag=1;
                    break;
                }
            }
            if(flag){
                printf("YES\n");
                printf("%d\n",num);
                for(int i=0;i<num;i++){
                    printf("%d %d\n",oper[i].x,oper[i].y);
                }
            }else{
                printf("NO\n");
            }

        }

    }
    return 0;
}

  

时间: 2024-11-05 04:55:39

HDU 5353—— Average——————【贪心+枚举】的相关文章

HDU 5353 Average 贪心

就是贪心啊,不知道为啥总是不过,总是WA 方法不对吗? 将数组扩展一倍,从左到右扫描,大于平均数就给右边的,小于就从右边拿,等于就不变,记录下操作类型. 大于2直接NO,应该是正确的算法吧,自己出了一些数据也都过了 1 #pragma comment(linker, "/STACK:102400000,102400000") 2 #include <iostream> 3 #include <cstdio> 4 #include <fstream>

HDU 5353 Average(平分值,求步聚)多校6

Average Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1948    Accepted Submission(s): 495 Special Judge Problem Description There are n soda sitting around a round table. soda are numbered

HDU 5353 Average

题意:有n个人坐在圆桌上,每个人带着糖果若干,每次只能给旁边的人1科糖果,而且坐相邻的两个人最多只能给一次(要么你给我,要么我给你),问是否能将糖果平均分了. 思路:明显每个人最多只能多于平均值2个糖果,因为他只能分别往左和右边的人给1颗.而多于平均值1的人可以任意选1个方向,只要到最后所有人满足了即可.多余糖果超过3的.平均数是浮点型的都是无解. 在第i和第i+1个人之间建两条边(即无向边拆成2条有向边),分别从一方指向另一方.1和n也建两条.分两步: (1)将持有2个多余糖果的人先处理,用D

hdu 4898 LCP+贪心思维

题意:将一个字符串切成k块,使得字典序最大的那块最小. ORZ  WJMZBMR,几行题解读了一天才懂. 快速比较两个子串的大小可以利用LCP(最长公共前缀),比较公共前缀的下一个字符的大小就够了. 利用这种思想,首先我们可以预处理所有子串的LCP(后缀数组+记录 O(2nlog(2n))+O(n*n),dp(O(4*n*n))) 然后将这些子串利用LCP按照字典序排序,开始二分答案. 二分的答案就是这K个块字典序的上限.假设以i作为起点,由于字典序上限已知,所以我们可以立刻求出i点最远能选到哪

思维/构造 HDOJ 5353 Average

题目传送门 1 /* 2 思维/构造:赛后补的,当时觉得3题可以交差了,没想到这题也是可以做的.一看到这题就想到了UVA_11300(求最小交换数) 3 这题是简化版,只要判断行不行和行的方案就可以了,做法是枚举x[1],x[n]的所有可能,x[2~n-1]能递推出来 4 x[i]表示i给i+1的值(0/-1/1) 那么 a[i] - x[i] + x[i-1] == ave,详细看代码 5 */ 6 /**********************************************

hdu 4869 Task(贪心)

题目链接:hdu 4869 Task 题目大意:有n台机器,m个任务,每个机器和任务都有有xi和yi,要求机器的xi,yi均大于等于任务的xi和yi才能执行任务.每台机器一天只能执行一个任务.要求完成的任务数尽量多,并且说金额尽量大.完成每个任务的金额为xi?500+yi?2 解题思路:贪心,mach[i][j]表示等级为i,时间为j的机器数量,task[i][j]表示等级为i,时间为j的机器数量.每次优先减少i,因为对应等级减少100,对应的金额代价也不会减少超过500(即时间减少1). 每次

POJ 2965-The Pilots Brothers&#39; refrigerator(贪心+枚举)

The Pilots Brothers' refrigerator Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19464   Accepted: 7462   Special Judge Description The game "The Pilots Brothers: following the stripy elephant" has a quest where a player needs to o

HDU 4864 Task(贪心)

HDU 4864 Task 题目链接 题意:有一些机器和一些任务,都有时间和等级,机器能做任务的条件为时间等级都大于等于任务,并且一个任务只能被一个机器做,现在求最大能完成任务,并且保证金钱尽量多 思路:贪心,对于每个任务,时间大的优先去匹配,时间相同的,等级大的优先去匹配,因为时间占得多,时间多1就多500,而等级最多才差200.然后匹配的时候,尽量使用等级小的去匹配,而时间只要大于它的都可以用,因为是按时间优先,所以如果该时间能匹配大的,其他肯定也能匹配,那么肯定优先匹配大的,所以只要在等级

HDU 4811 Ball(贪心)

2014-05-15 22:02 by Jeff Li 前言 系列文章:[传送门] 马上快要期末考试了,为了学点什么.就准备这系列的博客,记录复习的成果. 正文-计数  概率 概率论研究随机事件.它源于赌徒的研究.即使是今天,概率论也常用于赌博.随机事件的结果是否只凭运气呢?高明的赌徒发现了赌博中的规律.尽管我无法预知事件的具体结果,但我可以了解每种结果出现的可能性.这是概率论的核心. "概率"到底是什么?这在数学上还有争议."频率派"认为概率是重复尝试多次,某种结