传送门:Kabaleo Lite
题意
有n道菜,1≤n≤105,a[i]是每道菜可以赚的钱,−109≤ ai ≤109,b[i]是这道菜的个数,1≤bi≤105,你每次只能选从1开始连续的菜,然后问最多有多少顾客,并且顾客最多的前提下赚的钱最多是多少。
题解
这个题的重点在于会用__int128,我都没见过,好菜呜呜。
- 从数据可以看出,爆long long了,一开始没发现,和队友疯狂wa,然后还是不会负数的大数,赛后发现可以用__int128,__int128的用法见:https://blog.csdn.net/shadandeajian/article/details/81843805 。
- 首先要求顾客最多,并且只能从第一道菜开始卖,所以最大顾客数就是b[1]。
- 用c数组记录 1~i 道菜盈利的前缀和,假设 j>i 并且 c[i] < c[j],那肯定是要卖 1~j 更赚钱。假设j<i,并且c[i] < c[j],那肯定也是要卖 1~j 更赚钱。优先队列里用两个pair,c数组为第一关键字,1~i 中b[i]的最小值为第二关键字,原本是第几道菜为第三关键字。用cnt记录已经卖给几个人了,pos记录最小的卖完的菜品下标。在队列里如果队顶的第二关键字>cnt,并且第三关键字 < pos,说明可以更新答案,将第一关键字加到ans中,并更新pos和cnt,直到队列为空。
代码
1 #include<bits/stdc++.h> 2 #define ll __int128 3 #define pii pair<ll,pair<ll,ll> > 4 using namespace std; 5 6 inline __int128 read(){ 7 __int128 x=0,f=1; 8 char ch=getchar(); 9 while(ch<'0'||ch>'9'){ 10 if(ch=='-') 11 f=-1; 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9'){ 15 x=x*10+ch-'0'; 16 ch=getchar(); 17 } 18 return x*f; 19 } 20 21 inline void print(__int128 x){ 22 if(x<0){ 23 putchar('-'); 24 x=-x; 25 } 26 if(x>9) 27 print(x/10); 28 putchar(x%10+'0'); 29 } 30 31 const ll maxn=1e5+10; 32 ll a[maxn],b[maxn],c[maxn]; 33 priority_queue<pii> q; 34 35 int main() 36 { 37 38 ll t; 39 t=read(); 40 ll kk=1; 41 while(t--){ 42 ll n; 43 n=read(); 44 for(ll i=0;i<n;i++) a[i]=read(); 45 for(ll i=0;i<n;i++) b[i]=read(); 46 for(ll i=0;i<n;i++){ 47 if(i) c[i]=c[i-1]+a[i]; 48 else c[i]=a[i]; 49 } 50 __int128 ans=0; 51 ll bb=b[0]; 52 for(ll i=0;i<n;i++){ 53 bb=min(bb,b[i]); 54 q.push({c[i],{bb,i}}); 55 } 56 ll cnt=0,pos=n; 57 while(!q.empty()){ 58 ll x=q.top().first,y=q.top().second.first,z=q.top().second.second; 59 q.pop(); 60 if(y<=cnt||pos<=z) continue; 61 ans+=x*(y-cnt); 62 cnt=y; 63 pos=z; 64 } 65 cout<<"Case #"; 66 print(kk++); 67 cout<<": "; 68 print(b[0]); 69 cout<<" "; 70 print(ans); 71 cout<<endl; 72 } 73 return 0; 74 }