Loading

题解:P6902 [ICPC2014 WF] Surveillance

可以在 cnblog 中阅读。

考虑弱化版链怎么做,每次选取左端点在当前位置前面的线段,跳到其中最大的右端点,可以维护一个数组表示起点为 \(i\) 的目标位置,可以做到 \(O(n+k)\)

考虑多次询问一段区间 \([l,r]\) 的答案,这时如果暴力从 \(l-1\) 开始跳是 \(O(n^2)\) 的,只需要一个倍增数组即可 \(O(\log n)\) 完成跳跃动作。

原题的做法也与之类似,一个处理环状问题的经典操作是复制一倍数组。这时对于复制后每个长度为 \(n\) 的区间都代表原环上的一个循环置换,那通过上面的区间询问做法,可以对每个长度为 \(n\) 的区间做询问,取答案最小值即为答案。

时间复杂度 \(O(n \log n)\)

#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)

typedef pair<int,int> pii;

const int N=1e6+5,LG=25;
int n,k;
pii a[N];
int f[N*2][LG];

signed main()
{
	IOS;
	cin>>n>>k;
	for(int i=1;i<=k;i++)
	{
		cin>>a[i].first>>a[i].second;
		if(a[i].first>a[i].second) a[i].second+=n;
	} 
	sort(a+1,a+k+1);
	int r=0,tot=0;
	for(int i=1;i<=n*2;i++)
	{
		while(tot+1<=k&&a[tot+1].first<=i)
			r=max(r,a[++tot].second+1);
		f[i][0]=r;
	}
	for(int j=1;j<=20;j++)
		for(int i=1;i<=n*2;i++) 
			f[i][j]=f[f[i][j-1]][j-1];
	int ans=0x3f3f3f3f;
	for(int i=1;i<=n;i++)
	{
		int p=i,res=0;
		for(int j=20;j>=0;j--)
		{
			if(f[p][j]<i+n) 
				p=f[p][j], res+=(1<<j);
		}
		res++, p=f[p][0];
		if(p>=i+n) ans=min(ans,res);
	}
	if(ans>=0x3f3f3f3f) cout<<"impossible"<<endl;
	else cout<<ans<<endl;
	return 0;
}
posted @ 2024-09-30 15:44  tai_chi  阅读(0)  评论(0编辑  收藏  举报