__int128(例題:2020牛客多校第八場K題)
題意:
有n道菜,第i道菜的利潤為\(a_i\),且有\(b_i\)盤。你要按照下列要求給顧客上菜。
1.每位顧客至少有一道菜
2.給顧客上菜時,都必須從第一道菜開始,上連續的編號的菜,例如,你可能給一位顧客 上的菜為第一道,第二道,第三道,但是不能為只上第二道而不上第一道,或者第一道,第三道中間缺少第二道。求這些菜能夠容納的最大顧客數,並且求出在容納最多顧客時的利潤最大為多少。
輸入輸出
有t組樣例,沒組樣例第一行為\(n\),表示有n道菜,接下來共有兩行,第一行n個數\(a_1,a_2 ... a_n\),第i個數表示第i種菜的利潤,第二行為n個數\(b_1,b_2...b_n\),第i個數表示第i種菜的個數。
資料範圍
\(1\le n\le 10^{5}\),\(-10^{9}\le a_i\le10^{9}\),\(1\le b_i\le10^{5}\)
輸入
2
3
2 -1 3
3 2 1
4
3 -2 3 -1
4 2 1 2
輸出
Case #1: 3 8
Case #2: 4 13
說明
對於測試案例1,最大訪問者數量為3,一種可能的解決方案是:
第一位訪客獲得食物1,利潤是2。
第二位訪客獲得食物1,利潤為2。
第三位訪客獲得食物1 +食物2 +食物3,利潤為2 +(-1)+ 3。
題解
1.由於必須上第一道菜,因此第一道菜的數量即為最大招待顧客的數量。
2.計算最大利潤時,採用貪心策略,在滿足條件時,優先選取利潤最大的即可,由於每次選取 1~i的連續的菜,可以先求出前i份菜的利潤的字首和。然後按利潤字首和大小排序,從大到小遍歷,對於前n份菜利潤為sum的貢獻計算方法為,求出前n種菜剩餘的菜的最小的數量 min,讓答案累加\(min*sum\),然後將前n種菜的數量都減去min,這個操作可以用線段樹來進行區間查詢和修改。
3.由於答案最大值為 \(10^{19}\),稍微超過了long long int的範圍,因此c++要採用 __int128,__int128為128位的整數,是gcc的擴充套件,大小範圍在 [\(2^{127},2^{127}-1\)].且在windows環境下的gcc不支援編譯,在linux環境下的gcc支援編譯,不過沒有對應的輸入輸出函式,要自定義輸入輸出函式。
__int128模板
`inline __int128 read(){//讀入
__int128 x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void fprint(__int128 x){//輸出。
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
fprint(x/10);
putchar(x%10+'0');
}`
題目完整code
#include<bits/stdc++.h>
#define scd(x) scanf("%d",&x)
#define scdd(x,y) scanf("%d%d",&x,&y)
#define sclld(x) scanf("%lld",&x)
#define sclldd(x,y) scanf("%lld%lld",&x,&y)
#define print(x) cout<<x<<endl
#define CLR(a) memset(a,0,sizeof(a))
#define ls (rt<<1)
#define rs (rt<<1|1)
using namespace std;
typedef long long ll;
typedef double db;
const double eps = 1e-7;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const ll mod = ll(1e9)+7;
const int maxn=int(2e5)+500;
template<typename tp>inline tp lowbit(tp x){return x&(-x);}
template<typename tp_>void debug(tp_ x) {cout<<"*********** "<<x<<" *************"<<endl;}
template<typename tp1_,typename tp2_>void debug(tp1_ x,tp2_ y){cout<<"*********** "<<x<<" "<<y<<" *************"<<endl;}
struct P{int x;__int128 y;P(){}P(int _x,__int128 _y):x(_x),y(_y){}};
bool cmp(const P elem1,const P elem2){
if(elem1.y==elem2.y)return elem1.x>elem2.x;
return elem1.y<elem2.y;
}
__int128 a[maxn];
__int128 b[maxn];
P sum[maxn];
int Case = 1;
struct node{
__int128 sum;
__int128 lazy;
}tree[maxn<<2];
inline __int128 read(){
__int128 x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void fprint(__int128 x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
fprint(x/10);
putchar(x%10+'0');
}
void build(int rt,int l,int r){
tree[rt].sum=tree[rt].lazy=0;
if(l==r){
tree[rt].sum = b[l];
return ;
}
int mid = (l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
tree[rt].sum = min(tree[ls].sum,tree[rs].sum);
}
void pushdown(int rt,int l,int r){
if(tree[rt].lazy){
__int128 val = tree[rt].lazy;
tree[ls].sum-=val;
tree[rs].sum-=val;
tree[ls].lazy += val;
tree[rs].lazy += val;
tree[rt].lazy = 0;
}
}
void update(int rt,int l,int r,int L,int R,__int128 val){
if(l>=L&&r<=R){
tree[rt].sum -=val;
tree[rt].lazy += val;
return ;
}
pushdown(rt,l,r);
int mid= (l+r)>>1;
if(L<=mid)update(ls,l,mid,L,R,val);
if(R>mid)update(rs,mid+1,r,L,R,val);
tree[rt].sum = min(tree[ls].sum,tree[rs].sum);
}
__int128 ask(int rt,int l,int r,int L,int R){
if(l>=L&&r<=R){
return tree[rt].sum;
}
pushdown(rt,l,r);
int mid = (l+r)>>1;
__int128 res = inf;
if(L<=mid)res=min(res,ask(ls,l,mid,L,R));
if(R>mid)res=min(res,ask(rs,mid+1,r,L,R));
return res;
}
void solve() {
int n;
scd(n);
sum[0].y = 0;
for(int i=1;i<=n;i++){
a[i]=read();
sum[i].x=i;
sum[i].y=a[i]+sum[i-1].y;
}
for(int i=1;i<=n;i++)b[i]=read();
sort(sum+1,sum+n+1,cmp);
__int128 visit = b[1];
build(1,1,n);
__int128 ans = 0;
for(int i=n;i>=1;i--){
__int128 cnt = ask(1,1,n,1,sum[i].x);
ans+= cnt*sum[i].y;
update(1,1,n,1,sum[i].x,cnt);
}
printf("Case #%d: ",Case);
fprint(visit);
printf(" ");
fprint(ans);
printf("\n");
}
void Main(){
int _;
scd(_);
while(_--)
solve(),++Case;
}
//#define _Debug
int main(){
#ifdef _Debug
freopen("data.in","r",stdin);
clock_t b = clock();
Main();
clock_t e = clock();
cout<<"the time of cost is "<<(e-b)<<endl;
#else
Main();
#endif
return 0;
}