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;
}