2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest A Toda2 贪心

/*
    题目描述:给出n个人的分数,每轮选出2~5个人,把他们的分数减1,现要求把所有人的分数全部变成t,要求t最大,
           输出每一轮选人的策略。
                    
    思路:注意两个性质:
                1、每轮选2个或3个人,因为如果有一轮选了4个人,可以分成两轮每轮选两个人;如果有一轮选了5个人,可
                    以分成两轮,一轮选2个人,一轮选3个人
                2、如果最终所有人的分数是t(即保证t是可以实现的分数的前提下),所有人初始时的分数总和是sum,那
                    么sum-n*t如果是偶数的话,一定可以通过每一轮选两个人来实现;如果是奇数的话,一定可以通过有一轮
                    选3人,其余每轮选两人来实现。
*/
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 1e2 + 5 ;
int ans[maxn * maxn][maxn] , r[maxn] , n ;
struct node
{
    int val , num ;
    bool operator<(const node & rhs)const
    {
        return val < rhs.val ;
    }
};
int solve(int x)
{
    mem(ans ,0) ;
    priority_queue<node>Q;
    int sum = 0;
    for(int i = 1 ; i<= n ; i++){
        node st = {r[i] - x , i} ;
        if(st.val != 0){
            sum += st.val ;
            Q.push(st) ;
        }
    }
    int cnt = Q.size() , cur = 1 ;
    node y[4] ;
    if(sum & 1){
        if(cnt < 3)   return 0;
        for(int i = 1 ; i <= 3 ; i++){
            y[i] = Q.top();
            --y[i].val ;
            ++ans[cur][y[i].num];
            Q.pop();
        }
        for(int i = 1 ; i<= 3 ; i++){
            if(y[i].val != 0){
                Q.push(y[i]);
            }
        }
        ++cur;
    }
    while(!Q.empty()){
        for(int  i = 1 ; i<= 2 ; i++){
            y[i] = Q.top();
            Q.pop();
            ++ans[cur][y[i].num];
            --y[i].val ;
        }
        for(int i = 1 ; i<= 2 ; i++){
            if(y[i].val != 0){
                Q.push(y[i] ) ;
            }
        }
        ++cur;
        if(Q.size() == 1)
            return 0 ;
    }
    return (cur - 1 ) ;
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        int maxv = -1 , minv = INF , tag = 0 ;
        for(int i = 1 ; i<= n ; i++){
            scanf("%d",&r[i]);
            if(i >1 && r[i] != r[i-1])      tag = 1;
            minv = min(minv , r[i]) ;
            maxv = max(maxv , r[i]) ;
        }
        if(!tag){
            printf("%d\n0\n",r[1]);
            continue ;
        }
        int flag = 0 , res , t ;
        for(int i = minv ; i > 0  ; --i){
            if(t = solve(i)){
                flag = 1 ;
                res = i ;
                break;
            }
        }
        if(!flag){
            printf("%d\n%d\n", 0 , n * maxv);
            for(int i = 1 ; i<= n ; i++){
                for(int j = 1 ; j<= maxv ; j++){
                    for(int k = 1 ; k <= n ; k++){
                        if(k == 1 || k == 2 || k == i)
                            printf("1");
                        else
                            printf("0");
                    }
                    printf("\n") ;
                }
            }
        }
        else{
            printf("%d\n%d\n",res , t );
            for(int i = 1 ; i<= t ; i++){
                for(int j = 1 ; j<= n ; j++){
                    printf("%d",ans[i][j]);
                }
                printf("\n") ;
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值