Loading

CF1500F Cupboards Jumps

首先考虑差分,令 \(d_i=h_{i+1}-h_i\) ,可以发现 \(w_i=\max(|d_i|,|d_{i+1}|,|d_i+d_{i+1}|)\)

然后就可以得到一个 \(\mathcal O(nC)\) 的做法。

\(f_{i,j}\) 表示前 \(i\) 个数,将 \(j\) 作为结尾是否可行,然后分类讨论 \(w_i\) 是以上三种取值的哪一种就好了。

大概就这样子:

\[f_{i+1,w_i}=f_{i,x}(x\le w_i) \]

\[f_{i+1,x}=f_{i,w_i}(x\le w_i) \]

\[f_{i+1,x}=f_{i,w_i-x}(x\le w_i) \]

然后考虑每次转移的区间是如何变化的

  • \(f_{i+1,w_i}=f_{i,x}\) 表示:如果上一层存在 \([x,x](x\le w_i)\) ,则在这一层加入 \([w_i,w_i]\)
  • \(f_{i+1,x}=f_{i,w_i}\) 表示:如果上一层存在 \([w_i,w_i]\),则在这一层加入 \([0,w_i]\)
  • \(f_{i+1,x}=f_{i,w_i-x}\) 表示:如果上一层存在 \([l,r]\) ,则在这一层加入 \([w_i-r,w_i-l]\)

因此每一层最多增加一个区间即 \([w_i,w_i]\)

如果直接暴力维护这些区间,时间复杂度为 \(\mathcal O(n^2)\)

继续优化区间转移的过程。

可以发现如果出现了第二种转移,所有的区间都会被合并为一个区间 \([0,w_i]\)

而对于其他两种,都是将当前区间以 \(\frac{w_i}{2}\) 为中心翻转,再加上一个单点。

这个单点在之后的转移中数量始终为一个且会跟着翻转,而区间的数量始终有且只有一个。

于是考虑不再翻转每个点而是翻转整个数轴。

具体的,每次对数轴以零点为中心进行翻转,记录当前翻转次数和平移了多长即可。

接下来直接倒着求出一个合法方案就行。

#include<bits/stdc++.h>
#define int long long
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
int n,m;
int a[1111111],d[1111111],ans[1111111];
int tag1,tag2;
set<int>st;

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	int l=0,r=m;
	R(i,1,n-2)
	{
		cin>>a[i];
		int ll,rr,t;
		if(tag1&1) ll=tag2,rr=tag2-a[i];
		else ll=-tag2,rr=a[i]-tag2;
		t=rr;
		if(ll>rr) swap(ll,rr);
		l=max(l,ll),r=min(r,rr);
		while(st.size()&&(*st.begin())<ll) st.erase(st.begin());
		while(st.size()&&(*st.rbegin())>rr) st.erase(*st.rbegin());
		if(!st.size()&&l>r) 
		{
			cout<<"NO\n";
			return 0;
		}
		if(st.count(t)||(l<=t&&t<=r))
		{
			l=0,r=ans[i]=a[i];
			st.clear();
			tag1=tag2=0;
			continue;
		}
		if(l<=r)
		{
			if(tag1) ans[i]=tag2-l;
			else ans[i]=tag2+l;
		}
		else
		{
			int tt=*st.begin();
			if(tag1) ans[i]=tag2-tt;
			else ans[i]=tag2+tt;
		}
		tag1^=1;tag2=a[i]-tag2;
		if(tag1&1) t=tag2-a[i];
		else t=a[i]-tag2;
		st.emplace(t);
	}
	if(l<=r)
	{
		if(tag1) d[n-1]=tag2-l;
		else d[n-1]=tag2+l;
	}
	else
	{
		int tt=*st.begin();
		if(tag1) d[n-1]=tag2-tt;
		else d[n-1]=tag2+tt;
	}
	L(i,1,n-2)
	{
		if(ans[i]==a[i]) 
		{
			d[i]=a[i];
		}
		else if(d[i+1]==a[i]) d[i]=ans[i];
		else d[i]=a[i]-d[i+1];
	}
	int ret=1;
	L(i,1,n-2) 
	{
		if(abs(d[i])+abs(d[i+1])!=a[i]) ret*=-1;
		d[i]=ret*d[i];
	}
	ret=0;
	R(i,1,n-1) d[i]+=d[i-1],ret=min(ret,d[i]);
	cout<<"YES\n";
	R(i,1,n) cout<<d[i-1]-ret<<" ";
	cout<<endl;
}
posted @ 2022-03-07 21:54  yoisaki_hizeci  阅读(52)  评论(0)    收藏  举报