luoguP3584[POI2015]LAS题解

提供一个新颖的做法 先%一发 Itst

首先,把它看做一个环,点是食物,边是人。我们要把每条边定向。

环的细节自己判一下。对于 $ a_i > 2 \times a_{i+1} $ 或 $ a_i > 2 \times a_{i-1} $ 的人肯定直接选 $ i $ 食物。

如果整个环中没有这种情况,就直接朝一个方向选,很显然这样做是对的。

否则,对于每个一个已选的食物,我们直接让 $ a_i \leftarrow {a_i \over 2} $ 并把这个人删掉。很显然,这样删完之后,环形成了若干条链。对于每条链,都有这样一条性质: $ a_i \in [{a_{j} \over 2},a_j \times 2 ] ( j=i-1/i+1) $ 。因此,我们可以直接把链上的点权最小值抠出来,并以它为分界点,左边的选左边的食物,右边的选右边的食物。这样可以保证方案是对的。

还有一些细节看代码吧。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){
	int f=1,r=0;char c=getchar();
	while(!isdigit(c))f^=c=='-',c=getchar();
	while(isdigit(c))r=(r<<1)+(r<<3)+(c&15),c=getchar();
	return f?r:-r;
}
const int N=1e6+7;
int n,ans[N<<1];
ll a[N<<1];
int main(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=read()<<1;
	bool flg=1;
	for(int i=1;i<=n;i++){
		int j=i%n+1;
		if(a[i]>2*a[j])ans[i]=i,a[i]>>=1,flg=0;
		else if(a[i]*2<a[j])ans[i]=j,a[j]>>=1,flg=0;
	}
	for(int i=n;i;i--){
		if(ans[i])continue;int j=i%n+1;
		if(a[i]>2*a[j])ans[i]=i,a[i]>>=1,flg=0;
		else if(a[i]*2<a[j])ans[i]=j,a[j]>>=1,flg=0;
	}//可能有这样一种情况:7 4 1。这样有可能4除完后,7又要除,因而发生类似一种链式反应。我们可以通过正反都扫一遍来解决这一问题、
	if(flg){for(int i=1;i<=n;i++)printf("%d ",i);exit(0);}
	for(int i=1;i<=n;i++)a[i+n]=a[i];
	int Pos=0;
	for(int i=1;i<=n;i++)if(ans[i]){Pos=i;break;}
	for(int i=Pos;i<n+Pos;i++){
		if(ans[(i-1)%n+1])continue;
		int j=i;while(!ans[j%n+1] && j<n+Pos-1)j++;
		int pos=i;
		for(int k=i+1;k<=j+1;k++)
			if(a[pos]>a[k])pos=k;
		for(int k=i;k<pos;k++)ans[(k-1)%n+1]=(k-1)%n+1;
		for(int k=pos;k<=j;k++)ans[(k-1)%n+1]=k%n+1;
		i=j;
	}
	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
	return 0;
}

posted @ 2021-07-07 21:55  b1ts  阅读(83)  评论(0编辑  收藏  举报