教主的别墅(villa)
来源:互联网 发布:mac两个充电器的区别 编辑:程序博客网 时间:2024/04/27 14:49
第三题:教主的别墅(villa)
(villa.pas/cpp/in/out)
villa.in
villa.out
【题目背景】
LHX教主身为宇宙第一富翁,拥有一栋富丽堂皇的别墅,由于别墅实在太大了,于是教主雇佣了许许多多的人来负责别墅的卫生工作,我们不妨称这些人为LHXee。
【题目描述】
教主一共雇佣了N个LHXee,这些LHXee有男有女。
教主的大别墅一共有M个房间,现在所有的LHXee在教主面前排成了一排。教主要把N个LHXee分成恰好M个部分,每个部分在队列中都是连续的一段,然后分别去打扫M个房间。
教主身为全世界知识最渊博的人,他当然知道男女搭配干活不累的道理,以及狼多羊少,羊多狼少的危害之大。所以教主希望一个分配方式,使得所有小组男女个数差的最大值最小。
教主还希望你输出从左到右,每个组的人数。
如果有多种人数组合都能达到最优值,教主希望你分别告诉他这些方案中字典序最小和最大的方案。换句话说,你需要找到两种方案,这两种方案满足所有组男女个数差最大值最小的前提下,第一种方案(字典序最小)要越靠前的组人数越少,也就是让第一个小组人尽量少,并且在第一个小组人尽量少的前提下,让第二个小组的人尽量少,依此类推;第二种方案(字典序最大)则要让越靠前的组人数越多。
【输入格式】
输入的第1行为两个正整数N与M,用空格分隔。
第2行包含一个长度为N的串,仅由字符组成,第i 个字符为0表示在这个位置上的LHXee为女生,若为1则为男生。
【输出格式】
输出文件包含两行,每行M个正整数,正整数之间用空格隔开,行末无多余空格。这M个正整数从左到右描述了你所分的每个组的人数。
第1行为字典序最小的方案,第2行为字典序最大的方案。
【样例输入】
8 3
11001100
【样例输出】
1 2 5
5 2 1
【样例说明】
字典序最小的方案按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]大。
第一眼:二分,转化判定性问题
于是就慢慢慢慢分,写个dfs分吧~~~
然后再看:求出答案
这tm怎么求啊!!!!
于是慢慢慢慢求,写两个dfs吧~~~
果断T掉,还好有个35分不错了
我的Code:
//#define _TEST _TEST#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <cmath>#include <algorithm>using namespace std;/////////////////////////////////////////////////#define for0(i,j) for(int i=0;i<j;i++)#define for1(i,j) for(int i=1;i<=j;i++)#define clear(arr,x) memset(arr,x,sizeof(arr))/////////////////////////////////////////////////int n,m;int sum1[5000005]={0};char a[5000001];int ans1[100001],ans2[100001];int cnt1=0,cnt2=0;int num0=0;namespace LCT{ //////////////////////////////////}; ///////////////////////////////////////////////////////////////////////////////////void qin(int &ret){ char c;ret=0; while((c=getchar())<'0'||c>'9'); while(c>='0'&&c<='9')ret=ret*10+c-'0',c=getchar();}bool check(int s,int m,int cut){ if(cut==1) { if(abs(sum1[n]-sum1[s])<=m) return 1; else return 0; } for(int i=s+1;i<=n-cut+1;i++) { if(abs(sum1[i]-sum1[s])<=m&&check(i,m,cut-1)) return 1; } return 0;}bool dfs1(int s,int m,int cut){ if(cut==1) { if(abs(sum1[n]-sum1[s])<=m) { ans1[++cnt1]=n-s; for(int i=1;i<=cnt1;i++) printf("%d ",ans1[i]); return 1; } else return 0; } for(int i=s+1;i<=n-cut+1;i++) { ans1[++cnt1]=i-s; if(abs(sum1[i]-sum1[s])<=m&&dfs1(i,m,cut-1)) { return 1; } cnt1--; } return 0;}bool dfs2(int s,int m,int cut){ if(cut==1) { if(abs(sum1[n]-sum1[s])<=m) { ans2[++cnt2]=n-s; for(int i=1;i<=cnt2;i++) printf("%d ",ans2[i]); return 1; } else return 0; } for(int i=n-cut+1;i>=s+1;i--) { ans2[++cnt2]=i-s; if(abs(sum1[i]-sum1[s])<=m&&dfs2(i,m,cut-1)) { return 1; } cnt2--; } return 0;}/////////////////////////////////////////////////void input(){ qin(n); qin(m);// getchar(); for1(i,n) { a[i]=getchar()=='0'?-1:1; sum1[i]=sum1[i-1]+a[i]; if(sum1[i]==0)num0++; }}void solve(){ ///////////////////init/////////////////// int l=0,r=n/m+1,mid; int ans; ////////////////calculate//////////////// //if(num0>=m)r=0; while(l<r) { mid=(l+r)>>1; if(check(0,mid,m)) r=mid; else l=mid+1; } ans=l; l=1,r=1; dfs1(0,ans,m); puts(""); //for1(i,n)printf("%d ",sum2[i]); dfs2(0,ans,m); /////////////////output///////////////// /*puts(""); for(int i=cnt2;i>=1;i--) printf("%d ",ans2[i]);*/}/////////////////////////////////////////////////int main(){ #ifndef _TEST freopen("villa.in","r",stdin); freopen("villa.out","w",stdout); #endif input(); solve(); #ifdef _TEST for(;;); #endif return 0;}
这题尼玛用贪心、、咳咳、、、、
能贪个什么东西啊、、、
据网上神犇所说“易证:最优方案下,最大男女人数差ans=(abs(a[n])-1)/m+1(即上取整)”
AC Code~~~
最近是dev的tab出问题了吗?缩进成了这样、、、
//#define _TEST _TEST #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <cmath> #include <algorithm> using namespace std; ///////////////////////////////////////////////// #define for0(i,j) for(int i=0;i<j;i++) #define for1(i,j) for(int i=1;i<=j;i++) #define clear(arr,x) memset(arr,x,sizeof(arr)) ///////////////////////////////////////////////// const int maxn=5000000+10; int n,m; char s[maxn]; int dif[maxn]; int zero,ans,mis; int st[maxn]; ///////////////////////////////////////////////// inline int abs(int x){return x>0?x:-x;} void cal()//按每组人数字典序最小原则分组 {zero=0,mis=0;memset(dif,0,sizeof(dif));for(int i=0;i<n;i++){if(s[i]=='1')mis++;else mis--;dif[i]=mis;if(!mis)zero++; }if(!dif[n-1] && zero>=m){if(zero>=m)ans=0;else ans=1;}else ans=abs(abs(dif[n-1])-1)/m+1;int cnt=0,cur=-1;for(int i=0;i<n;i++){if(cnt>=m-1)//如果已经分了m-1组了,则将后面n-i人作为第m组就完工了 {st[cnt++]=n-i;break;} if(abs(dif[n-1]-dif[i])<=ans*(m-cnt-1))//后n-i人的男女差 = 总男女差 - 前面i人的男女差 <= 后m-cnt组*ans ,则可以按此分组 {st[cnt++]=i-cur;//将[cur+1,i]分为一组 cur=i;}}}/*void cal() { int cnt=0,cur=-1; zero=0,mis=0; clear(dif,0); for0(i,n) { if(s[i]=='1') mis++; else mis--; dif[i]=mis; if(!mis)zero++; } if(!dif[n-1]&&zero>=m) ans=0; else ans=abs(abs(dif[n-1])-1)/m+1; for0(i,n) { if(cnt>=m-1) { st[cnt++]=n-i; break; } if(abs(dif[n-1]-dif[i])<=ans*(m-cnt+1)) { st[cnt++]=i-cur; cur=i; } } } *////////////////////////////////////////////////// void input() { scanf("%d%d\n",&n,&m); gets(s); } void solve() { ///////////////////init/////////////////// ////////////////calculate//////////////// cal(); for0(i,m) printf("%d ",st[i]); puts(""); reverse(&s[0],&s[n]); cal(); for0(i,m) printf("%d ",st[m-i-1]); /////////////////output///////////////// } ///////////////////////////////////////////////// int main() { #ifndef _TEST freopen("villa.in","r",stdin); freopen("villa.out","w",stdout); #endif input(); solve(); #ifdef _TEST for(;;); #endif return 0; }
- 教主的别墅(villa)
- Orz教主第6次模拟赛之教主的别墅
- uva321 - The New Villa(新别墅)
- 别墅的空间设计
- 神奇的别墅
- 楼天城(楼教主)的ACM心路历程!
- vijos p1471 教主的游乐场(贪心)
- 楼教主的acm心路历程 (上)
- 楼教主的ACM心路历程(下)
- [BZOJ3343]教主的魔法(分块)
- 【BZOJ3343】教主的魔法(分块)
- BZOJ3343: 教主的魔法(分块)
- bzoj3343 教主的魔法 ( 分块 +二分)
- 灵动的别墅室内装修
- 教主的花园
- 【枚举】教主的花园
- 你们的“教主”是谁?
- 3343: 教主的魔法
- 让多个Fragment 切换时不重新实例化
- 约瑟夫环问题(Josephus)
- 急求大婶指导redis Could not get a resource from the pool 异常
- Android PopupWindow显示位置和显示大小
- AOJ-169 找零钱(记忆化搜索)
- 教主的别墅(villa)
- Phonegap自定义插件(cordova3.4)
- HDOJ 题目1133Buy the Ticket(大数,数学)
- 初识Heritrix
- 使用ADF Mobile开发手机Web应用
- 黑马程序员——IO流体系概览
- DateUtils日期转换工具
- 【leetcode】 Reverse Words in a String
- OpenGL glDrawBuffer()函数