【E题题解】

槽点:居然没看出来可以直接动态前缀和,我的,我的,下次我请y佬喝茶

OKK回顾下这题: 有钱的y佬带着 元钱去了围成一圈的 个happy茶商铺(第 家和第 家(首尾)相接),第 个茶铺以 元一杯出售happy茶,这y佬转圈买,走到一家,够钱就买一杯,不够就啥也不干,不论买不买都去下一个茶铺,钱花光为止

这哥们太富了下次V我50

看了一眼数据范围:



哇亚雷,前面一直在想怎么模拟转圈买,直到后来,想怎么模拟转到那个位置不买也不计数,好像线段树或者树状数组就能做了这样的话...

Whatever~

证明几个东西:

1.对于y佬绕到任意一圈(设第 圈),如果他买不了某家店铺(设第 家)的happy茶,那么他下一圈(如果还有的话)再转到这家店铺也一定买不了:
显然后面就算再逛到这第 家店之前不再花钱,情况一样,该买不起还是买不起,更别说万一还花钱了...

2.对于y佬之后都会不够钱的店,按茶价贵到便宜来确定并选择无视(经过但不买,也不计数,体现在线段树/树状数组中就是直接清了那家店铺的数据,价格清零,计次数也清零)逻辑上正确:
(下设 ) 由于(按价格从大到小排序意义上)价格贵的会先被清零,则考虑两种情况,一是价格贵的在价格便宜的店前面,即 ,则贵的店清零了以后再看便宜的店会不会清零具有显然的先后依据,不赘述;二是价格便宜的在价格贵的前面,即 ,此时依题意,不可能在买不起 店happy茶的同时买得起 店的茶,以上得证。
暗示做法:以价格为依据,对这组数据的副本排序(结构体排序更方便)

则,建树(线段树或前缀树状数组)按照原店铺顺序建,一圈算一轮,最终目的是为了搜索出一轮下来,剩下 元的y佬能经过 家店,花费 的钱去买奶茶,这样y佬就买到了 杯奶茶
复杂度情况:
建树
每次求区间操作
清理操作 总复杂度:
如果是线段树,常数 更大点儿
(可怜的我们都是y佬的队友耶)

思路理顺,c++代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll readll(){
	ll x=0,f=1;
	char k=getchar();
	while(k<'0'||k>'9'){
		if(k=='-')f=-1;
		k=getchar();
	}
	while(k>='0'&&k<='9'){
		x=(x<<3)+(x<<1)+(k-'0');
		k=getchar();
	}
	return x*f;
}
int readint(){
	int x=0,f=1;
	char k=getchar();
	while(k<'0'||k>'9'){
		if(k=='-')f=-1;
		k=getchar();
	}
	while(k>='0'&&k<='9'){
		x=(x<<3)+(x<<1)+(k-'0');
		k=getchar();
	}
	return x*f;
}
const int maxn=2e5+10;
ll a[maxn];
struct dat{
    ll val;
    int id;//按照原来店家的位置找到线段树叶子节点来清
}d[maxn];//结构体排序,作为对店清零的依据
bool cmp(dat a,dat b){
	return a.val>b.val;
}
ll tree[maxn*4]/*树的主体,记录价格总和*/,tstand[maxn*4]/*记还有多少家店没被清零*/,rec[maxn]/*我选择了在建树的时候存储某单家店对应的叶子节点,便于反向找到该节点并执行log_2n级别的清零*/;
void maketree(int x,int l,int r){
	//cout<<"Now going to tree "<<x<<endl;
	if(l==r){
		rec[l]=x;
		tree[x]=a[l];
		tstand[x]=1;
		//cout<<"Storing "<<a[l]<<"(pos:"<<l<<") at tree "<<x<<endl;
		return ;
	}
	int mid=(l+r)/2;
	maketree(x*2,l,mid);
	maketree(x*2+1,mid+1,r);
	tree[x]=tree[x*2]+tree[x*2+1];
	tstand[x]=tstand[x*2]+tstand[x*2+1];
	return ;
}
void clear_(int l){
	int now=rec[l],w=tree[rec[l]];
	while(now){
		tree[now]-=w;
		tstand[now]-=1;
		now>>=1;
	}
	return ;
}
int qpos(int x,int l,int r,ll w){
	//cout<<"Going to tree "<<x<<" (from "<<l<<" to "<<r<<", remain value:"<<w<<")"<<endl;
	if(l==r){
		//cout<<"Get a position ";
		if(w<tree[x]){
			//cout<<l-1<<endl;
			return l-1;
		}
		else{
			//cout<<l<<endl;
			return l;
		}
	}
	int mid=(l+r)/2;
	if(w>tree[x*2]){
		return qpos(x*2+1,mid+1,r,w-tree[x*2]);
	}
	else{
		return qpos(x*2,l,mid,w);
	}
}
ll q_sum(int x,int l,int r,int sl,int sr){
	//cout<<"Querying sum at tree "<<x<<"("<<sl<<" to "<<sr<<" & demand:"<<l<<" to "<<r<<")"<<endl;
	if(sl>=l&&sr<=r){
		//cout<<"Returning "<<tree[x]<<endl;
		//system("pause");
		return tree[x];
	}
	int mid=(sl+sr)/2;
	if(r<=mid){
		return q_sum(x*2,l,r,sl,mid);
	}
	else if(l>mid){
		return q_sum(x*2+1,l,r,mid+1,sr);
	}
	else{
		return q_sum(x*2,l,r,sl,mid)+q_sum(x*2+1,l,r,mid+1,sr);
	}
}
ll q_stand(int x,int l,int r,int sl,int sr){
	//cout<<"  Querying stands at tree "<<x<<"("<<sl<<" to "<<sr<<" & demand:"<<l<<" to "<<r<<")"<<endl;
	if(sl>=l&&sr<=r){
		//cout<<"  Found "<<tstand[x]<<" stands."<<endl;
		//system("pause");
		return tstand[x];
	}
	int mid=(sl+sr)/2;
	if(r<=mid){
		return q_stand(x*2,l,r,sl,mid);
	}
	else if(l>mid){
		return q_stand(x*2+1,l,r,mid+1,sr);
	}
	else{
		return q_stand(x*2,l,r,sl,mid)+q_stand(x*2+1,l,r,mid+1,sr);
	}
}
int n;
bool chk(ll rem,int pos){
	ll w=0;
	if(pos>1)w=q_sum(1,1,pos-1,1,n);
	return rem-w<a[pos];
}
int main(){
    n=readint();
    //cout<<n<<endl;
    ll t=readll(),sum=0,ans=0;
    for(int i=1;i<=n;i++){
    	a[i]=readll();
        sum+=a[i];
        d[i].id=i;
        d[i].val=a[i];
    }
    sort(d+1,d+1+n,cmp);
    maketree(1,1,n);
    //cout<<"Make tree done!"<<endl;
    int st=1;
    while(st<=n){
    	while(st<=n&&chk(t,d[st].id)){
    		//cout<<"!!!CLEARING STAND NO."<<d[st].id<<"!!!"<<endl;
    		clear_(d[st].id);
    		st++;
		}
		if(st>n)break;
		int pos=qpos(1,1,n,t);
		//cout<<"Remain "<<t<<" while found position "<<pos<<endl;
		if(pos<=0)break;
		ll w=q_sum(1,1,pos,1,n),stand_=q_stand(1,1,pos,1,n);
		//cout<<"  * sum up "<<w<<" ("<<stand_<<" stand(s)"<<endl;
		ans+=t/w*(stand_);
		t%=w;
	}
	printf("%lld\n",ans);
    return 0;
}