luogu_P3584 [POI2015]LAS

传送门:https://www.luogu.org/problem/P3584

据说对人设状态会很复杂,所以就针对食物来设置状态

f[i][0/1/2/3]分别表示不被吃/被左吃/被右吃/被都吃

接下来看转移方程(依据是,在什么情况下前面那个人会做出当前选择,而不选别的选择显然是当前最优,更改后不会更优啊

  1. 不被吃,那前一个人为什么不吃c[i]?如果c[i-1]是一个人吃那么状态就是由f[i-1][2]转移而来(c[i-1]>c[i]),如果两个人吃由f[i-1][3]转移而来(c[i-1]/2>c[i])
  2. 被左边吃,前一个人为什么选择c[i]?如果c[i-1]被左边人吃则状态由f[i-1][1]转移而来(c[i-1]/2<c[i]),如果不被吃由f[i-1][0]转移而来(c[i-1]<c[i])
  3. 被右边吃,前一个人为什么不吃它?如果c[i-1]被右边人吃则状态由f[i-1][2]转移而来(c[i-1]>c[i]/2),如果被两个人吃由f[i-1][3]转移而来(c[i-1]/2>c[i]/2)
  4. 被都吃,那前一个人为什么选择分享而不吃左边?如果c[i-1]被左边吃则状态由f[i-1][1]转移而来(c[i-1]/2<c[i]/2),如果不被吃由f[i-1][0]转移而来(c[i-1]<c[i]/2

最后因为是环,所以我们先枚举第一个食物的状态,然后看最后这个状态是否是最优状态(即是否合法)

//代码巨丑...
#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;
}
View Code
原文地址:https://www.cnblogs.com/coclhy/p/11633401.html