首页 > 其他分享 >题解 [ABC338D] Island Tour

题解 [ABC338D] Island Tour

时间:2024-01-29 19:25:03浏览次数:33  
标签:vert int 题解 LL long Tour MAXN Island include

【洛谷博客】

被降智的一道简单题。

题意

\(n\) 个岛屿,第 \(i\) 座桥连接 \(i\) 和 \(i+1\)(第 \(N\) 座桥连接着 \(1\) 和 \(N\))。

有一条长度为 \(M\) 的旅游序列 \(X\),你需要按照顺序依次经过这些点,选择断掉一座桥使得旅游经过的桥最少。

分析

设断掉第 \(i\) 座桥会因为绕行增加旅行长度的值为 \(s_i\)。

从 \(p\) 点到 \(q\) 点的最短距离是 \(\min(\vert p-q \vert , n - \vert p - q \vert )\),那么分类讨论。

不妨设 \(p<q\)。

设多绕行的距离为 \(d = \left\vert n - 2(q - p) \right\vert\)。

分类讨论三种情况。

当 \(q-p < n-(q-p)\) 时

如果断掉了 \(p \sim q-1\) 之间任意一座桥,总的旅程就会增加 \(d\),所以 \(\forall i \in [p,q), s_i \gets s_i+d\)。

当 \(q-p > n-(q-p)\) 时

如果断掉了 \(1 \sim p-1\) 或 \(q \sim n\) 之间任意一座桥,总的旅程就会增加 \(d\),所以 \(\forall i \in [1,p) \cup [q,n], s_i \gets s_i+d\)。

当 \(q-p = n-(q-p)\) 时

无论怎么走路程都是一样的,所以不处理。

然后这就是一个区间修改单点查询的问题,可以使用线段树,但是因为只在最后查询,所以可以使用差分。

线段树修改查询为 \(O(n \log n)\),差分修改查询为 \(O(n)\)。

代码

赛时的线段树做法

//the code is from chenjh
#include<iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 200002
using namespace std;
typedef long long LL;
int n,m;
int x[MAXN];
LL mn[MAXN<<2],lazy[MAXN<<2];//线段树区间修改维护最小值。
#define lson (rt<<1)
#define rson (rt<<1|1)
using ci=const int;
void pd(ci rt,ci l,ci r){
	mn[lson]+=lazy[rt],lazy[lson]+=lazy[rt];
	mn[rson]+=lazy[rt],lazy[rson]+=lazy[rt];
	lazy[rt]=0;
}
void update(ci rt,ci l,ci r,ci L,ci R,ci val){
	if(L<=l && r<=R){mn[rt]+=val,lazy[rt]+=val;return;}
	pd(rt,l,r);
	int mid=(l+r)>>1;
	if(L<=mid) update(lson,l,mid,L,R,val);
	if(mid<R) update(rson,mid+1,r,L,R,val);
	mn[rt]=min(mn[lson],mn[rson]);
}
LL query(ci rt,ci l,ci r,ci L,ci R){
	if(L<=l && r<=R) return mn[rt];
	pd(rt,l,r);
	int mid=(l+r)>>1;
	LL ret=0x3f3f3f3f3f3f3f3fll;
	if(L<=mid) ret=min(ret,query(lson,l,mid,L,R));
	if(mid<R) ret=min(ret,query(rson,mid+1,r,L,R));
	return ret;
}
int main(){
	cin>>n>>m;
	LL ans=0;
	for(int i=1;i<=m;i++) cin>>x[i];
	for(int i=2;i<=m;i++) ans+=min(abs(x[i]-x[i-1]),n-abs(x[i]-x[i-1]));//不断桥的最小距离。
	for(int i=2;i<=m;i++){
		int p=x[i-1],q=x[i];
		if(p>q) swap(p,q);
		if(((q-p)<<1)<n) update(1,1,n,p,q-1,n-((q-p)<<1));
		else if(((q-p)<<1)>n){
			if(p>1) update(1,1,n,1,p-1,((q-p)<<1)-n);
			update(1,1,n,q,n,((q-p)<<1)-n);
		}//线段树修改。
	}
	LL mn=0x3f3f3f3f3f3f3f3fll;
	for(int i=1;i<=n;i++) mn=min(mn,query(1,1,n,i,i));//线段树单点查询。
	printf("%lld\n",ans+mn);
	return 0;
}

复杂度更优秀的差分做法

//the code is from chenjh
#include<cstdio>
#include<algorithm>
#define MAXN 200002
using namespace std;
typedef long long LL;
int n,m;
int x[MAXN];
LL s[MAXN];
int main(){
	scanf("%d%d",&n,&m);
	LL ans=0;
	for(int i=1;i<=m;i++) scanf("%d",&x[i]);
	for(int i=2;i<=m;i++){
		int p=x[i-1],q=x[i];
		if(p>q) swap(p,q);
		ans+=min(q-p,n-q+p);//不断桥的最小距离。
		if(((q-p)<<1)<n) s[p]+=n-((q-p)<<1),s[q]-=n-((q-p)<<1);
		else if(((q-p)<<1)>n){
			s[1]+=((q-p)<<1)-n,s[p]-=((q-p)<<1)-n;
			s[q]+=((q-p)<<1)-n;
		}//差分修改。
	}
	LL mn=0x3f3f3f3f3f3f3f3fll;
	for(int i=1;i<=n;i++) mn=min(mn,s[i]+=s[i-1]);//差分还原的同时取增加的最小值。
	printf("%lld\n",ans+mn);
	return 0;
}

标签:vert,int,题解,LL,long,Tour,MAXN,Island,include
From: https://www.cnblogs.com/Chen-Jinhui/p/17995147/solution-at-abc338-d

相关文章

  • P10114 [LMXOI Round 1] Size 题解
    题目链接:[LMXOIRound1]Size挺有意思的诈骗题,其实这类题都喜欢批一个外壳,例如数据范围提示之类的。记得以前遇到的很多诈骗题,有一道cf的高分题,问的是区间出现次数的次数\(mex\),这玩意一开始感觉好难,出现次数还简单,还要考虑次数的次数,所以带修莫队的时候,一直没法确定怎么解决......
  • NOI 2017 蚯蚓排队 题解
    Meaning给定一些数字,对它们进行首尾相接和断开两种操作。对于每次询问,求对于每个数字,其后长度一定的数字串在给定数字串中出现的次数,并给出这些次数之积。Soultion对于每次首尾相接或断开的操作,如果直接对断点或合点两侧的整个数字串进行操作,时间复杂度不可接受。由于每次查询......
  • CF1764H Doremy's Paint 2 题解
    题目链接:CF或者洛谷高分题,感觉挺有意思的题,值得一提的是这个题的\(1\)和\(3\)版本却是两个基础题。一开始以为跟这道差不多:P8512[YnoiEasyRound2021]TEST_152题解。后面重新读了一下发现一个有趣的点:也就是是说操作的\(val\)并不太好搞了,如果\(val\)确定就基......
  • P5400 [CTS2019] 随机立方体 题解
    题目链接点击打开链接题目解法参考cmd的博客好复杂的推式子题,而且三维的对我来说好难想象/ll首先二项式反演,把恰好\(k\)个变成求至少\(i\)个的方案数令极大格子有至少\(i\)个的方案数为\(f_i\),\(R=\min\{n,m,k\}\)特判掉\(k>R\)答案为\(0\)根据二项式反演,答案......
  • P1438 无聊的数列 题解
    背景看到题解都是差分,竟然还有建两颗线段树和二阶差分的大佬。我感到不理解,很不理解。题目正解本题正解很明显就是:线段树是的,你没有看错,就只有线段树。很显然我们直接按照线段树板题写就可以了,维护题目需要维护的,注意到只有单点查询,所以我们根本不需要维护区间和,对于区间来......
  • 洛谷P10114题解
    题意简述给定一个长度为\(n\)的序列,求\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}{((d_i\oplusd_j)+(d_i\otimesd_j))}\)。思维路径观察数据范围可以发现\(n\le2\times10^6\)而\(\sum\limitsd_i\le5\times10^7\),这说明\(d\)数组中的重复值较多,直接枚举数值可......
  • 洛谷题解-[ABC325E] Our clients, please wait a moment
    https://www.luogu.com.cn/problem/AT_abc325_e题目描述ある国には都市がNNN個あります。あなたは、都市111にある営業所から000個以上の都市を経由して都市NNNにある訪問先へ移動しようとしています。移動手段は社用車と電車の222種類があります。都市......
  • 洛谷P10115题解
    题意简述给定一个括号序列,求整个序列的美丽值最大。思维路径见到序列和权值,很容易想到需要用DP。我们定义\(f[i][j]\)表示第\(1\)到\(i\)个括号产生的美丽值最大值,其中\(j=0\)表示第\(i\)个括号本身不参与美丽值贡献,\(j=1\)表示第\(i\)个括号本身参与美丽值贡献......
  • B3929 [GESP202312 五级] 小杨的幸运数 题解
    因为一些众所周知的原因,不放代码。分享一种考场思路:\(a\le10^7\),顺序查找肯定会废,所以可以用一种类似埃氏筛的方法将所有满足条件的数标记一下,并将其加入一个答案数组\(a\)当中。然后每次查询只需要用lower_bound函数二分查找一下,假如找到了第\(i\)个:\(a_i=x\),直接......
  • P7324 [WC2021] 表达式求值 题解
    题目链接点击打开链接题目解法不错的题首先建出表达式树说实话我一开始不知道怎么建,但看了代码之后就懂了这里简单说一下:假如要对区间\([l,r]\)建树,分\(E_r=)\)和\(E_r\neq)\)的情况\(E_r=)\),找到匹配的左括号,递归下去建树\(E_r\neq)\),\(r\)可以作为单独的一个......