题意:
有一个人捡按一定顺序捡石头,每秒都能捡起一个,但是他有时会分心,这是不但不能举石头,
而且手中的石头还会掉,直到没有石头可以掉下来或者掉下来的石头的总重量>k。依次给出n个
石头的重量和m个他分心的时间点,问他需要多长时间把石头全部举起。
分析:
n、m的范围都是 10^5,在不分心的时间都是每秒举起一个石头,那么用ti表示他分心的时间点,则
ti秒时,他的pos=p1,t(i+1)秒时在pos = p1+t(i+1)-ti-1处,然后要看他丢掉石头后回到哪个位置。
开始用O(n)的复杂度 去找那个位置j判断sum[pos+1]-sum[j]是否>k超时。
后来想到这个位置其实可以用二分 O(logn)的复杂度找出。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#define maxn 100010
using namespace std;
typedef long long ll;
int t[maxn];
ll sum[maxn];
int check(int l,int r,ll val)
{
int p;
while(l<=r)
{
int mid = (l+r)>>1;
if(sum[mid] < val)
{
p = mid;
l = mid+1;
}
else r = mid-1;
}
return p;
}
int main()
{
int n,m,k,w;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
memset(t,0,sizeof(t));
sum[0] = 0;
for(int i=1;i<=n;i++)
{
scanf("%d",&w);
sum[i] = sum[i-1]+w;
}
for(int i=1;i<=m;i++)
scanf("%d",&t[i]);
int pos = 0,ans = 0;
for(int i=1;i<=m;i++)
{
if(pos+t[i]-t[i-1]-1>=n)
{
ans += (n-pos);
pos = n;
break;
}
pos+=(t[i]-t[i-1]-1);
ans = t[i];
pos = check(1,pos+1,sum[pos]-k);
}
if(pos<n)
ans += (n-pos);
printf("%d\n",ans);
}
return 0;
}