[Codeforces713E][DP]Sonya Partymaker

33 篇文章 0 订阅

翻译

在这里插入图片描述

题解

注意一个人确定了一个方向就不会改变…
容易想到二分+ d p dp dp判断
然后考场上就想了个假飞的做法23333333
我们考虑怎么check
首先能够发现是答案的上界是最长的一段,不妨把这一段转到 1 1 1 n n n之间,为什么稍后会介绍
把这个问题扔到序列上做的话,我们可以这样 d p dp dp
f [ i ] f[i] f[i]表示覆盖完了 [ 1 , i ] [1,i] [1,i],往后最远还能覆盖到多少
转移的话,如果 f [ i − 1 ] f[i-1] f[i1]能覆盖到 i i i,那么可以直接修改为 a [ i ] + m i d a[i]+mid a[i]+mid
否则如果需要 i i i向左移动的话并且能够覆盖,那么对 a [ i ] a[i] a[i]取max
还有一种就是,我们可以让 i − 1 i-1 i1这个点往右移动,这个建立在 i i i向左移动能覆盖掉 i − 1 i-1 i1之上,如果可以的话,那么对 a [ i − 1 ] + m i d a[i-1]+mid a[i1]+mid取max
那么序列上的问题就做完了
我们考虑拓展到环上,由于我们将最长的一段移动到了 1 , n 1,n 1,n之间,所以 n n n这个点一定不能与 2 2 2一起覆盖掉 1 1 1,即 n n n不会跨过最长的那段,那么需要考虑的只是 1 1 1向左走或者 1 1 1向右走了
剩余就与序列上的问题相同

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=500005;
int ps[2*MAXN],n,m;
int f[2*MAXN],bg1,bg11;
bool check(int mid)
{
	bool tf=true;
	for(int k=1;k<=2&&k<=n;k++)
	{
		f[k]=(k==1?0:max(mid,ps[2]));
		for(int i=k+1;i<=n;i++)
		{
			f[i]=f[i-1];
			if(f[i-1]>=ps[i]-1)f[i]=max(f[i],ps[i]+mid);
			if(f[i-1]>=ps[i]-mid-1)f[i]=max(f[i],ps[i]);
			if(i>=k+2&&f[i-2]>=ps[i]-mid-1)f[i]=max(f[i],ps[i-1]+mid);
		}
		if(f[n]>=min(m-1,m+ps[k]-mid-1))return true;
	}
	return false;
}
int main()
{
//	freopen("quarts.in","r",stdin);
//	freopen("quarts.out","w",stdout);
	m=read();n=read();
	for(int i=1;i<=n;i++)ps[i]=ps[i+n]=read(),ps[i+n]+=m;
	if(n==1)return pr2(m-1),0;
	int mx=0;
	for(int i=1;i<=n;i++)if(ps[i+1]-ps[i]>mx)mx=ps[i+1]-ps[i],bg1=i,bg11=i+1;
	for(int i=1;i<=n;i++)ps[i]=ps[bg11+i-1];
	for(int i=2;i<=n;i++)ps[i]-=(ps[1]);ps[1]=0;
//	check(138);
	int l=0,r=1e9,ans;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(check(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	pr2(ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值