1 条题解

  • 0
    @ 2026-9-23 23:24:09

    考虑当前加入一个新点该放在什么位置。设放在位置 xx,左右两边距离其最近的点位置为 ll 和 rr。则 xx 一定要在 ll 到 rr 中间,即 xx 等于 l+r2\dfrac{l+r}{2}。

    最直观的想法是将两点之间的段都放入一个大根堆中。每次加入一个点就取出堆顶的段并分成两段加入堆中。对于每次询问,我们考虑离线来做。每加入点判断能否更新答案。

    该做法的时间复杂度是 O((n+k)log⁡(n+k))O((n+k)\log(n+k)),无法通过。

    考虑优化。因为每次加入一个点都会导致该段一分为二,使得段数巨大,所以考虑优化段数。我们发现将区间一分为二后左右两段长度相等,所以出现了很多相邻而长度相等的段。因此我们可以将这些段放在一起考虑。

    具体来说,我们对于堆中的每个元素,维护若干个三元组 (len,st,cnt)(len,st,cnt),表示从位置 stst 开始有连续的 cntcnt 个长度为 lenlen 的段。那么每加入点时,当前三元组就可以被替换为 (len/2,st,cnt×2)(len/2,st,cnt\times 2)。每替换一次相当于加入 cntcnt 个点。将询问从小到大排序,能更新答案就更新即可。复杂度 O(nlog⁡k)O(n\log k)。

    细节部分,lenlen 要表现为分数形式 xy\dfrac{x}{y},用结构体存起来,记得要开 __int128。

    #include<bits/stdc++.h>
    using namespace std;
    long long n,X,z,a[1000010];
    struct question{
    	long long num,id;
    }Q[100010];
    template<typename T>inline void write(T x){
    	if(x<0)putchar('-'),x=(~x)+1;
    	if(x>9)write(x/10);
    	putchar(x%10^48);
    }
    struct number{
    	__int128 x,y;
    	bool operator<(const number b)const{
    		return x*b.y<b.x*y;
    	}
    	number operator*(const number b)const{
    		number res;
    		res.x=x*b.x,res.y=y*b.y;
    		long long L=__gcd(res.x,res.y);
    		return (number){res.x/L,res.y/L};
    	}
    	number operator/(const number b)const{
    		return (number){x,y}*(number){b.y,b.x};
    	}
    	number operator+(const number b)const{
    		number res;
    		res.x=x*b.y+b.x*y,res.y=y*b.y;
    		long long L=__gcd(res.x,res.y);
    		return (number){res.x/L,res.y/L};
    	}
    }ans[100010];
    struct node{
    	number len;
    	long long st,cnt;
    	bool operator<(const node b)const{
    		if(len.x!=b.len.x||len.y!=b.len.y)return len<b.len;
    		else return st>b.st;
    	}
    };
    priority_queue<node>q;
    bool cmp(question x,question y){
    	return x.num<y.num;
    }
    int main(){
    	scanf("%lld%lld%lld",&n,&X,&z);
    	for(int i=1;i<=n;++i){
    		scanf("%lld",&a[i]);
    		if(i>=2)q.push((node){(number){a[i]-a[i-1],1},a[i-1],1});
    	}
    	for(int i=1;i<=z;++i)scanf("%lld",&Q[i].num),Q[i].id=i;
    	sort(Q+1,Q+z+1,cmp);
    	long long idx=1,tot=0;
    	while(idx<=z){
    		node u=q.top();
    		q.pop();
    		number l=u.len*(number){1,2};
    		while(idx<=z&&tot+u.cnt>=Q[idx].num){
    			ans[Q[idx].id]=(number){u.st,1}+l+((number){Q[idx].num-tot-1,1}*u.len);//求答案
    			idx++;
    		}
    		tot+=u.cnt;
    		q.push((node){l,u.st,u.cnt<<1});
    	}
    	for(int i=1;i<=z;++i)write(ans[i].x),putchar('/'),write(ans[i].y),puts("");
    	return 0;
    }
    
    • 1

    [POI 2020/2021 R2] 沙滩游客 / Plażowicze

    信息

    ID
    7537
    时间
    7000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者