阅读 184

Codeforces 713E. Sonya Partymakert 题解

Codeforces 713E. Sonya Partymakert 题解

阅读目录

  • Codeforces 713E. Sonya Partymaker

回到顶部

Codeforces 713E. Sonya Partymaker

Link!

题意

给出nn个人在环上的位置,环长为mm,可以给每个人钦点一个方向,每个人每秒钟沿着钦定方向走一步,问全环都被人走过的最小时间。

题解

先二分时间xx,考虑如何判断当前时间是否合法。

考虑破环为链,最后合并答案。

f[i]f[i]表示前ii个人最远能覆盖到哪里,p[i]p[i]表示第ii个人的位置。

分当前的向左还是向右讨论。

还要考虑一种特殊情况为第i1,ii−1,i之间的空由i+1i+1来向左填,让ii向右扩展,f[i]f[i]f[i2]f[i−2]转移即可。

为什么不会有i1,ii−1,i之间的空由i+2i+2来向左填的情况?

答:如果p[i+2]x<p[i]p[i+2]−x<p[i](即i+2i+2能够覆盖到i1,ii−1,i之间的空),那么有p[i]+x>p[i+2]p[i]+x>p[i+2],于是i,i+2i,i+2之间的空已经被ii覆盖,将向左的i+2i+2改为i+1i+1向左,i+2i+2向右一定更优。

考虑合并时11向左可能覆盖到nn,会干扰状态转移,于是选取最长的一段空破环为链,取空的长度为二分上界,于是1,n1,n之间不会互相覆盖。注意讨论11向左或向右,做两次dpdp即可。

难点总结

dpdp转移并非很难,难点在于观察到只会有i+1i+1回头填i1,ii−1,i之间的空,以及选取最长的区间破环为链,避免干扰转移。

Code

#include<bits/stdc++.h>#define ll long long#define N 200015#define rep(i,a,n) for (int i=a;i<=n;i++)#define per(i,a,n) for (int i=n;i>=a;i--)#define inf 0x3f3f3f3f#define pb push_back#define mp make_pair#define pii pair<int,int>#define fi first#define se second#define lowbit(i) ((i)&(-i))#define VI vector<int>#define all(x) x.begin(),x.end()#define SZ(x) ((int)x.size())using namespace std;int n,m,a[N],p[N],f[N];bool check(int x){
	f[1] = 0;	// < - 1
	rep(i,2,n){
		f[i] = f[i-1];		if(f[i-1] >= p[i] - 1) f[i] = max(f[i],p[i] + x);		if(f[i-1] >= p[i] - x - 1) f[i] = max(f[i],p[i]);		if(i > 2 && f[i-2] >= p[i] - x - 1) f[i] = max(f[i],p[i-1] + x);
	}	if(f[n] >= m - 1 - x) return 1;	// 1 - >
	if(p[1] + x < p[2] - x) return 0;
	f[2] = max(p[1] + x,p[2]);
	rep(i,3,n){
		f[i] = f[i-1];		if(f[i-1] >= p[i] - 1) f[i] = max(f[i],p[i] + x);		if(f[i-1] >= p[i] - x - 1) f[i] = max(f[i],p[i]);		if(i > 2 && f[i-2] >= p[i] - x - 1) f[i] = max(f[i],p[i-1] + x);
	}	if(f[n] >= m - 1 - max(x - p[2],0)) return 1;	return 0;
}int main(){	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d%d",&m,&n);
	rep(i,1,n) scanf("%d",&a[i]),a[i+n] = a[i] + m;
	sort(a+1,a+n+n+1);	if(n == 1){		printf("%d\n",m-1);		return 0;
	}	int pos = 2;	int l = 0,r;
	rep(i,2,n+1) if(a[i] - a[i-1] > a[pos] - a[pos-1]) pos = i;
	r = a[pos] - a[pos-1] - 1;
	rep(i,1,n) p[i] = a[i+pos-1];	int st = p[1];
	rep(i,1,n) p[i] -= st;	int ans = 114514;	while(l <= r){		int mid = (l+r)>>1;		if(check(mid)) ans = mid,r = mid-1;		else l = mid+1;
	}	printf("%d\n",ans);	return 0;
}

来源:https://www.cnblogs.com/czdzx/p/14810427.html

服务器评测 http://www.cncsto.com/ 

服务器测评 http://www.cncsto.com/ 


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐