Description
有一个人捡按一定顺序捡石头,每秒都能捡起一个,但是他有时会分心,这是不但不能举石头,而且手中的石头还会掉,直到没有石头可以掉下来或者掉下来的石头的总重量>k。依次给出n个石头的重量和m个他分心的时间点,问他需要多长时间把石头全部举起
Input
第一行三个整数n,m,k分别表示石头数量,分心次数以及每次分心掉落石头质量的下限,之后n行每行一个整数分别表示每个石头的质量,最后m行每行一个整数表示分心的时刻
Output
输出需要多长时间把石头全部举起
Sample Input
5 1 4
1
2
3
4
5
4
Sample Output
8
Solution
n、m的范围都是 10^5,在不分心的时间都是每秒举起一个石头,那么用ti表示他分心的时间点,则ti秒时,他的pos=p1,t(i+1)秒时在pos = p1+t(i+1)-ti-1处,然后二分求出他丢掉石头后回到哪个位置,即sum[pos+1]-sum[j]>k的pos点即可
Code
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
#define maxn 111111
ll n,m,k,sum[maxn],t[maxn];
ll goto_bound(ll l,ll r,ll v)
{
ll ans;
while(l<=r)
{
ll mid=(l+r)/2;
if(sum[mid]<v)
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
return ans;
}
int main()
{
while(~scanf("%I64d%I64d%I64d",&n,&m,&k))
{
memset(sum,0,sizeof(sum));
for(ll i=1;i<=n;i++)
{
ll temp;
scanf("%I64d",&temp);
sum[i]=sum[i-1]+temp;
}
t[0]=0;
for(ll i=1;i<=m;i++)
scanf("%I64d",&t[i]);
ll ans=0,pos=0;
for(ll i=1;i<=m;i++)
{
if(pos+t[i]-t[i-1]-1>=n)//如果在下一次分心点之前已经将全部石头举起
{
ans+=n-pos;
pos=n;
break;
}
ans=t[i];
pos+=t[i]-t[i-1]-1;
pos=goto_bound(1,pos+1,sum[pos]-k);//二分找到掉落石头后的位置
}
if(pos<n)
ans+=n-pos;
printf("%I64d\n",ans);
}
}