题目描述
ls最近开了一家图书馆,大家听说是ls开的,纷纷过来借书,自然就会出现供不应求的情况, 并且借书的过程类 似一个队列,每次有人来借书就将它加至队尾,每次有人来还书就把书借给队头的若干个人,定义每个人的等待时 间为拿到书的时刻减去加至队列的时刻,如果一个人根本就拿不到书,则等待时间为inf,现在给出所有时刻借书 还书的情况,和若干个询问,每次询问当图书馆初始有x本书时所有人的等待时间之和是多少(如果存在一个人根 本拿不到书,则输出INFINITY) 1<=n,q<=100000
Sol
[一费2/1 把 书 给 我!]
我们先考虑开始书的数量为0的时候,显然我们可以O(N)计算出每个点需要等待的人数,而总的等待时间就是每个点等待的人数求一下和233
考虑修改开始的书的数量到K的过程,其实就是把后面每个点的等待人数减去K,再把大于0的部分求一下和
那么现在我们就有一个非常显然的思路,二分
我们先根据每个点有多少个人在等待排一下序,排序完之后 我们每次就可以用一个log的效率去查找第一个被减去K不小于0的人的位置,然后求一个后缀和就可以了
至于无解的判断就是在K=0的时候,最后一个时间的等待的人数大于开始给的人数,就无解啦233
代码细节还是挺多的…建议考虑清楚再写…[多写了个等号挂了1个小时….]
Code
- #include <bits/stdc++.h>
- using namespace std;
- int N,Q,T[100005],K[100005],Now,NNow;
- long long Suffix[100005],Suffix1[100005];
- struct Node
- {
- int c;
- int T;
- }node[100005];
- int temp(Node x,Node y){return x.c<y.c;}
- char c[100005];
- char qwq[10005];
- int main()
- {
- freopen("expect.in","r",stdin);
- freopen("expect.out","w",stdout);
- cin>>N>>Q;
- for (int i=1;i<=N;i++)
- scanf("%s%d%d",&qwq,&T[i],&K[i]),c[i]=qwq[0];
- for (int i=1;i<=N;i++)
- {
- if (c[i]=='+') Now+=K[i];
- if (c[i]=='-') Now-=K[i];
- if (Now<0)
- node[i].c=-Now;
- if (i!=N)
- node[i].T=T[i+1]-T[i];
- }
- int rr=node[N].c;
- sort(node+1,node+N+1,temp);
- for (int i=N;i>=0;i--)
- {
- Suffix[i]=Suffix[i+1]+node[i].T;
- Suffix1[i]=Suffix1[i+1]+1ll*node[i].T*node[i].c*1ll;
- }
- for (int i=1;i<=Q;i++)
- {
- scanf("%d",&NNow);
- int l=0,r=N+1,anss=0;
- while (l<=r)
- {
- int mid=(l+r)>>1;
- if (node[mid].c<=NNow)
- l=mid+1;
- else r=mid-1,anss=mid;
- }
- if (NNow<rr)
- {
- printf("INFINITY ");
- continue;
- }
- if (anss==0)
- {
- printf("0 ");
- continue;
- }
- long long ans=(Suffix1[anss])-1ll*NNow*(Suffix[anss]);
- printf("%lld ",ans);
- }
- return 0;
- }