专栏文章
【题解】P12914 [POI 2020/2021 R2] 沙滩游客 / Plażowicze
P12914题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minaqf7t
- 此快照首次捕获于
- 2025/12/01 23:20 3 个月前
- 此快照最后确认于
- 2025/12/01 23:20 3 个月前
题意
给定一个有 个元素的序列 ,保证 。给定 次询问,每次询问会按照如下规则插入 个新元素:
- 令 为满足 最大的 中的最小值,在 和 中插入 。
求第 个插入元素的值。
思路
每次操作可以理解为把长度最大的区间劈成两半,考虑朴素做法,设一个大根堆,记 为某个区间左端点的位置, 为这个区间的长度,初始放入所有区间。每次取出堆顶的区间,把它劈成两半再放回堆中即可。
然后我们可以按 单调不降排序询问,每次模拟到当前的 。这样做时间复杂度为 ,显然无法通过。
由于 过大,考虑将其优化掉。我们发现一个区间被劈成两半后的两个区间本质是相同的,所以我们可以记 为这个区间包含几半, 为每半的长度, 为这个区间的左端点位置。弹出堆顶区间后可以发现必然会从左往右把这个区间的几半再劈开,所以共插入 个新元素,其中第 个被加入的元素值为 。之后我们只需把 减半, 翻倍,再放入堆中即可。
由于每轮操作最多 次弹出堆顶,最少让堆中所有的 翻倍,所以总的时间复杂度为 。
代码
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
struct fact{int x,y;};
bool operator<(const fact x,const fact y){return x.x*y.y<y.x*x.y;}
bool operator>(const fact x,const fact y){return x.x*y.y>y.x*x.y;}
bool operator==(const fact x,const fact y){return x.x*y.y==y.x*x.y;}
bool operator!=(const fact x,const fact y){return x.x*y.y!=y.x*x.y;}
struct data1{int k,id;}ask[N];
bool cmp(data1 x,data1 y){return x.k<y.k;}
struct data2
{
int pos,cnt;
fact len;
};
bool operator<(const data2 x,const data2 y){return(x.len!=y.len?x.len<y.len:x.pos>y.pos);}
bool operator>(const data2 x,const data2 y){return(x.len!=y.len?x.len>y.len:x.pos<y.pos);}
int a[N];
fact ans[N];
void solve()
{
int n,len,q;
cin>>n>>len>>q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=q;i++)cin>>ask[i].k,ask[i].id=i;
sort(ask+1,ask+q+1,cmp);
priority_queue<data2>heap;
for(int i=2;i<=n;i++)heap.push({a[i-1],1,{a[i]-a[i-1],1}});
int sum=0;
for(int i=1;;)
{
auto now=heap.top();
heap.pop();
fact tmp=now.len;
if((tmp.x&1)^1)tmp.x>>=1;
else tmp.y<<=1;
while(i<=q&&sum+now.cnt>=ask[i].k)
{
int id=ask[i].id;
ans[id]={now.pos*now.len.y+now.len.x*(ask[i].k-sum-1),now.len.y};
if(now.len.y!=tmp.y)ans[id].x<<=1,ans[id].y<<=1;
ans[id].x+=tmp.x,i++;
}
if(i>q)break;
heap.push({now.pos,now.cnt<<1,tmp});
sum+=now.cnt;
}
for(int i=1;i<=q;i++)
{
int gcd=__gcd(ans[i].x,ans[i].y);
cout<<ans[i].x/gcd<<'/'<<ans[i].y/gcd<<'\n';
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int _=1;
for(;_;_--)solve();
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...