BZOJ3749[POI2015] Łasuchy

本文介绍了一道名为Łasuchy的比赛题目,该题目要求合理分配圆桌上的食物以确保每个人都满意。通过动态规划的方法解决此问题,并给出了一种环形处理的实现思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BZOJ3749[POI2015] Łasuchy

Description

圆桌上摆放着n份食物,围成一圈,第i份食物所含热量为c[i]。

相邻两份食物之间坐着一个人,共有n个人。每个人有两种选择,吃自己左边或者右边的食物。如果两个人选择了同一份食物,这两个人会平分这份食物,每人获得一半的热量。

假如某个人改变自己的选择后(其他n-1个人的选择不变),可以使自己获得比原先更多的热量,那么这个人会不满意。

请你给每个人指定应该吃哪一份食物,使得所有人都能够满意。

Input

第一行一个整数n(2<=n<=1000000),表示食物的数量(即人数)。食物和人都从1~n编号。

第二行包含n个整数c[1],c[2],,c[n](1<=c[i]<=109)

假设第i个人(1<=i<n)左边是第i份食物,右边是第i+1份食物;而第n个人左边是第n份食物,右边是第1份食物。

Output

如果不存在这样的方案,仅输出一行NIE。

如果存在这样的方案,输出一行共n个整数,第i个整数表示第i个人选择的食物的编号。如果有多组这样的方案,输出任意一个即可。

Sample Input

5

5 3 7 2 9

Sample Output

2 3 3 5 1

Solution:

神奇dp题,调了一个下午…

首先这题是dp应该是显然的,考虑每个食物,有四种情况。

1

然后就可以写dp方程了,分情况讨论一下转移。

然后对于这个环形的处理采用了Claris大神的写法。首先枚举第一个食物的状态,用相同的方式从n向1转移一下,检查所枚举的状态是否能够实现,如果能就直接输出方案了,通过fa数组存一下当前状态从哪里转移过来,还原路径即可。

#include<stdio.h>
#include<ctype.h>
#include<string.h>
#define M 1000005
int A[M<<1],Ans[M];
bool dp[4][M<<1];
int fa[4][M<<1];
inline void Rd(int &res){
    char c;res=0;
    while(c=getchar(),!isdigit(c));
    do{
        res=(res<<1)+(res<<3)+(c^48);
    }while(c=getchar(),isdigit(c));
}
int main(){
    int n;
    Rd(n);
    for(int i=1;i<=n;i++)Rd(A[i]);
    A[0]=A[n];
    Ans[n-1]=-1;
    for(int k=0;k<4;k++){
        memset(dp,0,sizeof(dp));
        dp[k][1]=true;
        for(int i=2;i<=n;i++){
            if(dp[0][i-1]){
                if(A[i-1]*2>=A[i])dp[0][i]=true,fa[0][i]=0;
                if(A[i-1]>=A[i])dp[2][i]=true,fa[2][i]=0;
            }
            if(dp[1][i-1]){
                if(A[i-1]>=A[i])dp[0][i]=true,fa[0][i]=1;
                if(A[i-1]>=A[i]*2)dp[2][i]=true,fa[2][i]=1;
            }
            if(dp[2][i-1]){
                if(A[i]>=A[i-1]*2)dp[1][i]=true,fa[1][i]=2;
                if(A[i]>=A[i-1])dp[3][i]=true,fa[3][i]=2;
            }
            if(dp[3][i-1]){
                if(A[i]>=A[i-1])dp[1][i]=true,fa[1][i]=3;
                if(A[i]*2>=A[i-1])dp[3][i]=true,fa[3][i]=3;
            }
        }
        for(int i=0;i<4;i++)dp[i][1]=0;
        if(dp[0][n]){
            if(A[0]*2>=A[1])dp[0][1]=true,fa[0][1]=0;
            if(A[0]>=A[1])dp[2][1]=true,fa[2][1]=0;
        }
        if(dp[1][n]){
            if(A[0]>=A[1])dp[0][1]=true,fa[0][1]=1;
            if(A[0]>=A[1]*2)dp[2][1]=true,fa[2][1]=1;
        }
        if(dp[2][n]){
            if(A[1]>=A[0]*2)dp[1][1]=true,fa[1][1]=2;
            if(A[1]>=A[0])dp[3][1]=true,fa[3][1]=2;
        }
        if(dp[3][n]){
            if(A[1]>=A[0])dp[1][1]=true,fa[1][1]=3;
            if(A[1]*2>=A[0])dp[3][1]=true,fa[3][1]=3;
        }
        if(dp[k][1]){
            int t=fa[k][1];
            for(int j=n;j>=1;j--){
                Ans[j]=(t==0||t==1)?j:j%n+1;
                t=fa[t][j];
            }
            for(int i=1;i<=n;i++)
                printf("%d%c",Ans[i],i==n?'\n':' ');
            return 0;
        }
    }
    puts("NIE");
    return 0;
}