jzoj1795 教主的别墅 (贪心)

教主的别墅 (Standard IO)

Description

【题目背景】
  LHX教主身为宇宙第一富翁,拥有一栋富丽堂皇的别墅,由于别墅实在太大了,于是教主雇佣了许许多多的人来负责别墅的卫生工作,我们不妨称这些人为LHXee。

【题目描述】
  教主一共雇佣了N个LHXee,这些LHXee有男有女。
  教主的大别墅一共有M个房间,现在所有的LHXee在教主面前排成了一排。教主要把N个LHXee分成恰好M个部分,每个部分在队列中都是连续的一段,然后分别去打扫M个房间。
  教主身为全世界知识最渊博的人,他当然知道男女搭配干活不累的道理,以及狼多羊少,羊多狼少的危害之大。所以教主希望一个分配方式,使得所有小组男女个数差的最大值最小。
  教主还希望你输出从左到右,每个组的人数。
  如果有多种人数组合都能达到最优值,教主希望你分别告诉他这些方案中字典序最小和最大的方案。换句话说,你需要找到两种方案,这两种方案满足所有组男女个数差最大值最小的前提下,第一种方案(字典序最小)要越靠前的组人数越少,也就是让第一个小组人尽量少,并且在第一个小组人尽量少的前提下,让第二个小组的人尽量少,依此类推;第二种方案(字典序最大)则要让越靠前的组人数越多。

Input

  输入的第1行为两个正整数N与M,用空格分隔。
  第2行包含一个长度为N的串,仅由字符组成,第i 个字符为0表示在这个位置上的LHXee为女生,若为1则为男生。

Output

  输出文件包含两行,每行M个正整数,正整数之间用空格隔开,行末无多余空格。这M个正整数从左到右描述了你所分的每个组的人数。
  第1行为字典序最小的方案,第2行为字典序最大的方案。

Sample Input

8 3
11001100

Sample Output

1 2 5
5 2 1

Data Constraint

Hint

【样例说明】
  字典序最小的方案按1, 10, 01100分组,每组男女个数差的最大值为1,为最小。
  字典序最大的方案按11001, 10, 0分组。

【数据规模】
  对于40%的数据,有N ≤ 100;
  对于50%的数据,有N ≤ 1000;
  对于65%的数据,有N ≤ 100000;
  对于100%的数据,有N ≤ 5000000,M ≤ N且M ≤ 100000。

【提示】
关于字典序:
比较S1[N]与S2[N]的字典序大小,可以找到S1[N]与S2[N]中第1个不相同数字S1[i]与S2[i](即有对于所有1≤k<i,都有S1[k] =S2[k],但S1[i]≠S2[i])。如果S1[i]<S2[i],那么说S1[N]字典序比S2[N]小,否则说S1[N]字典序比S2[N]大。

分析:先求出男女生的差值尽量平均分配到m个房间.
用O(n)的时间扫一遍即得答案.
注意:差值为0(即男女生人数一样的时候)要特殊处理;
这分析还行

代码

#include <cstdio>
#include <cstring>
#include <string>
#define N 6000000
using namespace std;

int s[N],a[N],n,m,ans;
char c[N];

int abs(int x){return x>0?x:-x;}

int main()
{
    int x;
    scanf("%d%d",&n,&x);
    scanf("%s",c+1);
    for (int i=1;i<=n;i++) 
        if (c[i]=='1') s[i]=s[i-1]+1;
            else s[i]=s[i-1]-1;
    int m=x;
    ans=(abs(s[n])-1)/m+1;
    if (!s[n])
    {
        int tmp=0;
        for (int i=1;i<=n;i++)
            if (!s[i]) tmp++;
        if (tmp>=m) ans=0;
            else ans=1;
    }
    int k=0;
    for (int i=1;i<=n;i++)
    {
        if (s[i]-s[k]<=ans) 
        {
            int p=abs(s[n]-s[i])/(m-1);
            if (abs(s[n]-s[i])%(m-1)) p++;
            if (p<=ans)
            {
                printf("%d ",i-k);
                k=i;
                m--;
            }
        }
        if (m==1)
        {
            printf("%d\n",n-k);
            break;
        }
    }
    for (int i=n;i>=1;i--)
        if (c[i]=='1') s[i]=s[i+1]+1;
            else s[i]=s[i+1]-1;
    m=x;
    int tot=0;
    k=n+1;
    for (int i=n;i>0;i--)
    {
        if (s[k]-s[i]<=ans)
        {
            int p=abs(s[i]-s[1])/(m-1);
            if (abs(s[i]-s[1])%(m-1)) p++;
            if (p<=ans)
            {
                a[++tot]=k-i;
                k=i;
                m--;
            }
        }
        if (m==1) 
        {
            a[++tot]=k-1;
            break;
        }
    }
    for (int i=tot;i>=1;i--)
        printf("%d ",a[i]);
}

猜你喜欢

转载自blog.csdn.net/zhanghaoxian1/article/details/79283827
今日推荐