zoukankan      html  css  js  c++  java
  • [贪心][前缀和] JZOJ P1795 教主的别墅

    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

    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]大。

    题解

    • 我们把0当成-1做,跑一边前缀和
    • 用zero记录下有多少个位置为0
    • 如果zero比分组的组数多而且前缀和最后不为0,将x定为0(后面会解释x是什么)
    • 否则,将x定为abs(abs(sum[n-1])-1)/m+1(也就是将sum平均分到每一组的差值,向上取整)
    • 然后我们就可以模拟了,如果当前分了cnt>=m-1,将后面所有的数塞到第m组
    • 如果abs(sum[n-1]-sum[i])/(m-cnt-1)<=x,也就是将i处断后,后面的平均差值小于x,那当然是可以断的
    • 那么怎么满足字典序最小的条件呢?
    • 当然是有的取尽量先取
    • 就字典序最大时,将数组反过来再跑一遍,从大到小输出

    代码

     1 #include<cstdio>  
     2 #include<cstring>
     3 #include<iostream> 
     4 #include<algorithm>
     5 using namespace std;
     6 int n,m,sum[5000010],ans,fen[5000010];
     7 char s[5000010]; 
     8 int abs(int x){return x>0?x:-x;}  
     9 void greedy()
    10 {
    11     int cnt=0,num=-1,zero=0,k=0;
    12     memset(sum,0,sizeof(sum));
    13     for (int i=0;i<=n-1;i++)
    14     {
    15         if (s[i]=='1') k++; else k--;
    16         sum[i]=k;
    17         if (!k) zero++;
    18     }
    19     if (!sum[n-1]&&zero>=m) ans=0; else ans=abs(abs(sum[n-1])-1)/m+1;
    20     for (int i=0;i<=n-1;i++)
    21     {
    22         if (cnt>=m-1)
    23         {
    24             fen[cnt++]=n-i;
    25             break;
    26         }
    27         if (abs(sum[n-1]-sum[i])<=ans*(m-cnt-1))
    28         {
    29             fen[cnt++]=i-num;
    30             num=i;
    31         }
    32     }
    33 }
    34 int main()
    35 {  
    36     scanf("%d%d
    ",&n,&m);
    37     gets(s);
    38     greedy();
    39     for (int i=0;i<m;i++) printf("%d ",fen[i]);  printf("
    ");
    40     reverse(&s[0],&s[n]);
    41     greedy();
    42     for (int i=0;i<m;i++) printf("%d ",fen[m-i-1]);  
    43     return 0;
    44 } 
  • 相关阅读:
    SetWindowsHookEx详解
    C#使用全局钩子(hook),SetWindowsHookEx返回0、不回调的解决
    C#使用全局钩子(hook),SetWindowsHookEx返回0、不回调的解决
    how to get geometry type of layer using IMapServer3 and IMapLayerInfo? (C#)
    how to get geometry type of layer using IMapServer3 and IMapLayerInfo? (C#)
    windows cmd命令显示UTF8设置
    windows cmd命令显示UTF8设置
    C#写的NoSQL开源项目/系统(系列)
    TCP协议详解(2)
    红黑树
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8428199.html
Copyright © 2011-2022 走看看