luogu_P3584 [POI2015]LAS
传送门:https://www.luogu.org/problem/P3584
据说对人设状态会很复杂,所以就针对食物来设置状态
f[i][0/1/2/3]分别表示不被吃/被左吃/被右吃/被都吃
接下来看转移方程(依据是,在什么情况下前面那个人会做出当前选择,而不选别的选择显然是当前最优,更改后不会更优啊)
- 不被吃,那前一个人为什么不吃c[i]?如果c[i-1]是一个人吃那么状态就是由f[i-1][2]转移而来(c[i-1]>c[i]),如果两个人吃由f[i-1][3]转移而来(c[i-1]/2>c[i])
- 被左边吃,前一个人为什么选择c[i]?如果c[i-1]被左边人吃则状态由f[i-1][1]转移而来(c[i-1]/2<c[i]),如果不被吃由f[i-1][0]转移而来(c[i-1]<c[i])
- 被右边吃,前一个人为什么不吃它?如果c[i-1]被右边人吃则状态由f[i-1][2]转移而来(c[i-1]>c[i]/2),如果被两个人吃由f[i-1][3]转移而来(c[i-1]/2>c[i]/2)
- 被都吃,那前一个人为什么选择分享而不吃左边?如果c[i-1]被左边吃则状态由f[i-1][1]转移而来(c[i-1]/2<c[i]/2),如果不被吃由f[i-1][0]转移而来(c[i-1]<c[i]/2
最后因为是环,所以我们先枚举第一个食物的状态,然后看最后这个状态是否是最优状态(即是否合法)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//代码巨丑...
#include<cstdio>
#include<cstring>
#define R register
typedef long long ll;
using namespace std;
int n,c[1001000];
int f[1001000][4],ans[1001000];// 0_none 1_left 2_right 3_both
int main () {
scanf("%d",&n);
for(R int i=1;i<=n;i++) scanf("%d",&c[i]);
c[0]=c[n];c[n+1]=c[1];
for(R int i=0;i<=4;i++){
memset(f,-1,sizeof(f));
f[1][i]=i;
for(R int j=2;j<=n+1;j++){
if(f[j-1][3]!=-1&&c[j-1]>=c[j]<<1) f[j][0]=3;
if(f[j-1][2]!=-1&&c[j-1]>=c[j]) f[j][0]=2;
if(f[j-1][1]!=-1&&c[j]<<1>=c[j-1]) f[j][1]=1;
if(f[j-1][0]!=-1&&c[j]>=c[j-1]) f[j][1]=0;
if(f[j-1][2]!=-1&&c[j]<=c[j-1]<<1) f[j][2]=2;
if(f[j-1][3]!=-1&&c[j]<=c[j-1]) f[j][2]=3;
if(f[j-1][0]!=-1&&c[j]>=c[j-1]<<1) f[j][3]=0;
if(f[j-1][1]!=-1&&c[j]>=c[j-1]) f[j][3]=1;
}
if(f[n+1][i]!=-1){
int k=i;
for(R int j=n;j>=1;j--){
if(k==1) ans[j]=j%n+1;
else if(k==2) ans[j%n+1]=j%n+1;
else if(k==3) ans[j]=ans[j%n+1]=j%n+1;
k=f[j+1][k];
}
for(R int j=1;j<=n;j++) printf("%d ",ans[j]);
return 0;
}
}
printf("NIE");
return 0;
}