9.16-CSP-S开小灶5

T1 乌鸦喝水

经过赛后重新思考,我的做法其实并不需要什么吉司机,只需要一棵普通线段树,或者BIT也OK,然后只需要求一下它前后各有多少个大于等于它的数就行,做法是 \(O(n \log n)\)

简单来说就是考虑每个位置到底被喝了多少次,因为如果能喝一定喝,那么每个位置被喝的时间一定是从1开始的一段连续时间,于是考虑找到每个位置喝到什么时候不能喝了。 首先求出每个位置最多能被喝多少次,从小到大排序,然后逐个求解其被喝了多少次,将求解转化为判定,假设我们钦定它喝了 \(mid\) 轮,那么其后边的位置经历了 \(mid-1\) 轮,对于大于等于它的位置,这 \(mid-1\) 轮一定都被喝了,于是直接乘起来加上就行,对于比它小的位置,他们被喝了多少次都已经完成求解了,于是直接从数据结构里取出来就行,由于我们钦定了 \(mid\) ,在原二分做法下需要将他们的次数对 \(mid\)\(mid-1\)\(\min\) ,所以无脑上了吉司机。但是既然我们已经sort了,可以发现,当前我们解决的位置能被喝的次数,一定大于等于比它小的桶最多能喝的次数-1。

为什么是减一?因为可能这个更小的桶在前边,中间还经历了几个小桶,他们把大桶的可用次数消耗了,导致这一轮恰好大桶不能再喝了,但是既然这个小桶能喝到这一轮,那么大桶至少能喝到上一轮,否则小桶也喝不到这一轮。

于是这样我们可以设一个喝到的最大轮数为 \(p\) 的指针, 单调的移动它就行,移动不了的时候 check一下 \(p\) ,如果可行贡献就是 \(p\) ,否则就是 \(p-1\), p最多移动m次,每次移动一个log,因为在当前最大值为 \(p\) ,所以我们取值的时候也不用取min了,写个普通树就行

平衡树是因为我偷懒,实际上离散化一下上BIT就行。

点击查看代码
%:pragma GCC target("avx")
%:pragma GCC optimize(3)
%:pragma GCC optimize(2)
%:pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;

const int maxn=1e5+10;

#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<21;char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){ gc;while(*ip<'-')gc; bool f=*ip=='-';if(f)gc; int x=*ip&15;gc; while(*ip>'-'){x*=10;x+=*ip&15;gc;} return f ? -x : x; }
int n,m,Lim;
int w[maxn],a[maxn];
int ans;
int val[maxn];

struct FHQ_Treap{
	#define lch V[p].l
	#define rch V[p].r
	struct Vertex{int l,r,key,val,siz;}V[maxn];
	int tot,root;
	int New(int x){++tot;V[tot].l=V[tot].r=0;V[tot].val=x;V[tot].key=rand();V[tot].siz=1;return tot;}
	void Clear(){tot=root=0;}
	void Pushup(int p){V[p].siz=V[lch].siz+V[rch].siz+1;}
	void Split(int p,int &rtx,int &rty,int x){
		if(p==0)return rtx=rty=0,void();
		if(x<V[p].val){Split(V[p].l,rtx,V[p].l,x),rty=p,Pushup(rty);return;}
		else {Split(V[p].r,V[p].r,rty,x),rtx=p,Pushup(rtx);return;}
	}
	int Merge(int rtx,int rty){
		if(!rtx || !rty )return rtx|rty;
		if(V[rtx].key<V[rty].key){V[rtx].r=Merge(V[rtx].r,rty),Pushup(rtx);return rtx;}
		else {V[rty].l=Merge(rtx,V[rty].l),Pushup(rty);return rty;}
	}
	void Insert(int x){
		int l=0,r=0;Split(root,l,r,x);
		root=Merge(Merge(l,New(x)),r);
	}
	int Rank(int x){
		int l=0,r=0,res=0;
		Split(root,l,r,x-1),res=V[r].siz,root=Merge(l,r);
		return res;
	}
}T;

struct Seg{
	int tr[maxn<<2];
	void Pushup(int rt){tr[rt]=tr[rt<<1]+tr[rt<<1|1];}
	void Modify(int rt,int l,int r,int x,int w){
		if(l==r){return tr[rt]=w,void();}
		int mid=(l+r)>>1;
		if(x<=mid)Modify(rt<<1,l,mid,x,w);
		else Modify(rt<<1|1,mid+1,r,x,w);
		Pushup(rt);
	}
	int Query(int rt,int l,int r,int s,int t,int w){
		if(t<s)return 0;
		if(s<=l && t>=r)return tr[rt];
		int mid=(l+r)>>1,res=0;
		if(s<=mid)res+=Query(rt<<1,l,mid,s,t,w);
		if(t>mid)res+=Query(rt<<1|1,mid+1,r,s,t,w);
		return res;
	}
}E;

int pre;
int id[maxn];
int L[maxn],R[maxn];
vector<pii>vec;
int last,ts,mx=1;
bool cmp(const int &x,const int &y){if(val[x]==val[y])return x>y;else return val[x]<val[y];}

bool Check(int x,int mid){ return  val[x]>(R[x]+1)*(mid-1)+E.Query(1,1,n,x+1,n,mid-1)+L[x]*mid+E.Query(1,1,n,1,x-1,mid);}

void Sol(int x){
	if(val[x]!=last){
		for(auto it : vec)E.Modify(1,1,n,it.fir,it.sec);
		ts+=vec.size();vec.resize(0);
		last=val[x];
	}
	while(mx<m && Check(x,mx+1))++mx;
	if(Check(x,mx))vec.push_back(mair(x,mx)),ans+=mx;
	else vec.push_back(mair(x,mx-1)),ans+=mx-1;
}

void solve(){
	n=read(),m=read(),Lim=read();
	Rep(i,1,n)w[i]=read();Rep(i,1,n)a[i]=read(),id[i]=i;
	Rep(i,1,n)val[i]=(Lim-w[i])/a[i]+1;//,cerr<<val[i]<<" ";cerr<<"\n";
	Rep(i,1,n){ L[i]=T.Rank(val[i]); T.Insert(val[i]); }
	T.Clear();
	Dwn(i,n,1){ R[i]=T.Rank(val[i]); T.Insert(val[i]); }
	sort(id+1,id+n+1,cmp);
	Rep(i,1,n)Sol(id[i]);
	printf("%lld\n",ans);
}

#undef int
int main (){ return solve(),0; }

T2 kill

奇奇妙妙

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;

const int maxn=5e3+10;

int n,m,S;

int p[maxn],q[maxn];
bool vis[maxn];
vector<int>L,R;

int Get(int x,int y){return abs(p[x]-q[y])+abs(q[y]-S);}

bool Check(int Lim){
	Rep(i,1,m)vis[i]=false;
	int ip=1;
	for(auto it : L){
		while(ip<=m && (vis[ip] || Get(it,ip)>Lim))++ip;
		if(ip<=m)vis[ip]=true;
		else return false;
	}
	ip=m;
	for(auto it : R){
		while(ip>=1 && (vis[ip] || Get(it,ip)>Lim))--ip;
		if(ip>=1)vis[ip]=true;
		else return false;
	}

	return true;
}

void solve(){
	cin>>n>>m>>S;
	Rep(i,1,n)cin>>p[i],(p[i]>=S ? R.push_back(i) : L.push_back(i));Rep(i,1,m)cin>>q[i];
	sort(L.begin(),L.end()),sort(R.begin(),R.end()),sort(q+1,q+m+1);	
//	reverse(R.begin(),R.end());
	int l=-1,r=100000000000LL;
	while(r-l>1){
		int mid=(l+r)>>1;
		if(Check(mid))r=mid;
		else l=mid;
	}
	cout<<r<<"\n";
}

#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

posted @ 2022-09-17 09:34  Delov  阅读(12)  评论(0编辑  收藏  举报