题意:
有n种茶,n个人,第i种茶有 a[i]的量,第i个人一次能喝 b[i], 第i个人从第i种茶开始往前喝,求每个人最多能喝多少茶。
思路:
可以从后面往前面挪,用二分去寻找当前茶能有多少人喝(用后缀),然后如果有剩下的茶就在下一轮补上这个茶的值,然后
#include<cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <string> #include <math.h> #include<vector> #include<queue> #include<map> #define sc_int(x) scanf("%d", &x) #define sc_ll(x) scanf("%lld", &x) #define pr_ll(x) printf("%lld", x) #define pr_ll_n(x) printf("%lld\n", x) #define pr_int_n(x) printf("%d\n", x) #define ll long long using namespace std; const int N=1000000+100; int n ,m,h; ll s[N],a[N],cnta[N],res[N],cha[N];//差分数组 void slove( ) { int t; sc_int(n); for(int i =1;i<=n;i++)sc_int(s[n-i+1]); for(int i =1;i<=n;i++)sc_int(a[n-i+1]); for(int i =1;i<=n;i++)cnta[i]=cnta[i-1]+a[i];//前缀和数组 int sum=0; for(int i =1;i<=n;i++) { if(cnta[i]<=s[i]){ cha[1]++,cha[i+1]--;//差分操作 } else{ int l =i,r=1; while(l>r) { int mid=l+r>>1; if(cnta[i]-cnta[mid-1]<=s[i])l=mid; else r=mid+1; } if(cnta[i]-cnta[l-1]>s[i]) { res[l]+=s[i]; continue; } if(cnta[i]-cnta[l-1]!=s[i])res[l-1]+=s[i]-(cnta[i]-cnta[l-1]); cha[l]++,cha[i+1]--; } } res[0]=0; for(int i =1;i<=n;i++){ cha[i]+=cha[i-1]; res[i]+=cha[i]*a[i]; } for(int i =n;i>=1;i--){ cout<<res[i]<<" "; res[i]=res[i+1]=0; cha[i]=cha[i+1]=0; } cout<<endl; } int main() { int t; sc_int(t); while(t--) slove(); return 0; }
用差分去更新每个人能喝多少满的茶。