1 条题解
-
0
自动搬运
来自洛谷,原作者为

gyfer
**搬运于
2025-08-24 21:44:03,当前版本为作者最后更新于2018-07-25 23:48:40,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这是一道
模拟题思路:排序优化,模拟放置。
HINT:先把被别人覆盖的丢掉。环?复制一遍当做序列来做。对每个壁纸求出能接在它后面的右端点最大的。(怎么求?)那之后咋办啊(掀桌) 我会!枚举作为起点的牛,然后不断地往后跑直到覆盖一整圈! ......n元环了解一下? 把牛看作点,每个点有且只有一条出边...基环内向树! 点权为壁纸长度,边权为增加的有效长度。 只要起点点权+各边权和>=C就好了。 类似于two pointer,随着起点往后跳,终点也随着往后跳。 可惜的是不管是正向还是反向复杂度都好像是错的。。 。
首先把被完全覆盖的围栏去掉,剩下的按左端点升序排序。那么右端点肯定也是升序的了。。然后计算出每段围栏,它接下去一段围栏可达到的最远距离。枚举起点,贪心地一段一段接下去就可得到该起点的最优解。
直接这样做显然会T。。
正解
换个方向...考虑某个答案啥时候会被计算到。 显然不管是啥答案,肯定有条跨过环的边。 枚举那条边...然后呢?总不能直接跑吧对每个点x预处理出f[x],pos[x]:以x为起点,一直跳到 即将跨环 (再走一步就跨环了)的时候,走了几条边,停在哪里。枚举跨环的初始边(x,y),之后y直接跑到pos[y],然后稍微判断一下。
AC代码
#include<iostream> #include<algorithm> using namespace std; const int N=200001; const int INF=0x3f3f3f; struct node{ int l,r; }a[N]; int nxt[N],pos[N],jump[N],tmpcos[N]; int i,j,L,n,m,ans,k; bool cmp(node x,node y){ return x.l==y.l?x.r>y.r:x.l<y.l;//排序了解一下 } void get(int x){//得到当前牛所能到达的最远点 if(jump[x]) return; if(a[x].r>=L){ jump[x]=x; tmpcos[x]=0; }else{ get(nxt[x]); jump[x]=jump[nxt[x]]; tmpcos[x]=tmpcos[nxt[x]]+1; } } int main(){ cin>>L>>n; for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r,a[i].r+=a[i].l; sort(a+1,a+n+1,cmp); int mx=-1,tmp=0; for(int i=1;i<=n;i++)//缩牛操作 if(a[i].r>mx) { a[++tmp]=a[i]; mx=a[i].r; } n=tmp; tmp=0; for(int i=1;i<=n;i++){//计算pos nxt[i]=nxt[i-1]; for(;tmp<n&&a[tmp+1].l<=a[i].r;tmp++); if(tmp==i) nxt[i]=0; else{ nxt[i]=tmp; pos[i]=a[tmp].r; } //cout<<nxt[i]<<endl; } int tmpsum,now;//tmpsum:计算牛的总数 ans=INF; for(int i=1;i<=n;i++){ if(!jump[i]) get(i); tmpsum=tmpcos[i]+1; now=jump[i]; while(nxt[now]&&a[now].r<a[i].l+L&&tmpsum<ans){ now=nxt[now]; tmpsum++; } if(a[now].r>=a[i].l+L&&tmpsum<ans) ans=tmpsum; } cout<<ans<<endl; return 0; }
- 1
信息
- ID
- 2045
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者