TYZ 8/25 ranwen的烦恼

来源:互联网 发布:unity3d ui制作 编辑:程序博客网 时间:2024/06/05 14:20

冉文的烦恼

【问题描述】

冉文是个粗心的人,经常不小心把垃圾丢到地上。艾教实在没办法,只好派了m个学生,去捡冉文走过路上的垃圾。

假设冉文走过的路线是一条直线,每个位置分别是1..n,每个位置上垃圾的个数是ai。所有学生起始位置都在0,每秒钟,他们有两种选择:

1.向右走一步。

2.捡起一个地上的垃圾。

现在我们的问题是:要捡起冉文的所有垃圾,最少需要多少秒?

【输入格式】

第一行输入两个正整数n,m,如题目所述。

第二行输入n个非负整数ai,代表每个位置的垃圾个数。ai<=10^9

【输出格式】

一个数字,表示最少的时间。

【输入样例】

3 2

1 0 2

【输出样例】

5

解释:第一个学生走到3,然后捡2个垃圾,共花费时间5,第二个学生走到1,捡1个垃圾,共花费时间2。

【数据范围与约定】

对于30%的数据,m=1。

对于另30%的数据,m=2,垃圾总个数<=21。

对于100%的数据,n,m<=100000




题目的解答:

考试的时候不在乎你AC了多少题,只在乎你拿到了多少该拿的分数

30% m= =1的数据啊,直接暴力计算一下时间就好了,刚刚接触算法的人也会

30% m==2 的,一看到21,老司机们都知道这是要用dfs开车了

我考试的时候用dfs,但是注意这是辣鸡的总数21,我的dfs是按照光标位置搜索的,当n极大的时候(中间是铺天盖地的0),挂掉一个

再来说正解

记得不记得noip2015的挑石头,对于ans进行二分,没错这就是要做的事情

每个二分进行暴力的模拟,确定是否可行

从后往回模拟



#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<vector>using namespace std;typedef long long ll;int n,m,k;const ll maxn=100005;ll a[maxn];ll ans;const ll inf=0x3f3f3f3f;ll b[maxn];ll c[maxn];ll calb(){int rescur=-1;for(int i=n;i>=1;i--){if(b[i]){rescur=i;break;}}if(rescur==-1)return 0;int ressum=0;ressum+=rescur;for(int i=1;i<=rescur;i++){ressum+=b[i];}return ressum;}ll cala(){int rescur=-1;for(int i=n;i>=1;i--){if(a[i]){rescur=i;break;}}if(rescur==-1)return 0;int ressum=0;ressum+=rescur;for(int i=1;i<=rescur;i++){ressum+=a[i];}return ressum;}int lm;vector<int> q;bool check(ll t){ ll nm=m,extra=0; for(int i=1;i<=n;i++) { if(nm<a[i]/t) return 0; //如果人手不够,直接乱棍打死  else nm-=a[i]/t;//垃圾多于总时间,就得将记得伙计交代在这里  int left_task=a[i]%t; if(extra>=left_task) //壮劳力伤不起啊,剩余的时间叫做extra,可以用他干点别的  extra-=left_task; else {//当时如果被掏空了,就得重新找个伙计了  if(!nm) return 0; else { nm--,extra+=t-left_task; } } t--; if(!t) { for(int j=i+1;j<=n;j++) if(a[j]) return 0; //时间已经到了如果还有 //辣鸡你就死定了  } if(extra) extra--; //走路也是需要时间的!  } return 1;}int main(){cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];a[0]=inf;for(int i=n;i>=0;i--)if(a[i]!=0){n=i;break;}if(!n){cout<<0<<endl;return 0;}if(m==1){ans+=n;for(int i=1;i<=n;i++)ans+=a[i];cout<<ans<<endl;return 0;}if(m==2){ans=inf;    for(int i=1;i<=n;i++)    {if(a[i])    for(int j=1;j<=a[i];j++)    q.push_back(i);    }int lm=q.size();int _limit=1<<lm;for(int i=0;i<(_limit);i++){  for(int j=0;j<lm;j++)  {  if(i&(1<<j))  {  int xq=q[j];  a[xq]--;  b[xq]++;  }  }  //二进制枚举所有的状况,a可以带多少,随便带   ll nw=max(cala(),calb());  ans=min(ans,nw);  for(int j=0;j<lm;j++)  {  if(i&(1<<j))  {  int xq=q[j];  a[xq]++;  b[xq]--;  }  //回溯   }}cout<<ans<<endl;return 0;    }    else    {   ll r=2000000000000000,l=0;   while(r-l>1)   {   ll mid=(l+r)/2;   bool nw=check(mid);   if(nw)   r=mid;   else   l=mid;} cout<<l<<endl;//二分,不说了吧? }}



 

0 0
原创粉丝点击