洛谷P1043 数字游戏

题目描述:

传送门:https://www.luogu.com.cn/problem/P1043

 

 

解题思路:

由于是一个环,考虑将数组抄两遍

由于是区间和相乘,考虑用前缀和记录

由于是一个区间DP,考虑状态转移方程:

   设 f [i][j][k] 为区间 [i,j] 中有 k 个分段的最大值或最小值(设 ffmax为最大值,ffmin为最小值) 

   先枚举k,即目前已经被分为 k 个区间,再枚举区间的左端点和右端点,将状态分为两段:前k-1 段的最值+这一段的最值。枚举这个分界线在哪里,从而列出状态转移方程

由于要初始化,将 f[i][j][1] 赋值为sum[j] - sum[i-1] ,表示把点i到点j之间的数只分成一段的值

 

代码实现:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

inline int get()
{
    char c;
    int sign=1;
    while((c=getchar())<'0'||c>'9')
    {
        if(c=='-')
        {
            sign=-1;
        }
    }
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        res=res*10+c-'0';
    }
    return res*sign;
}

const int N=51,mod=10,M=10;
int n,m,ansmax=-1,ansmin=100000000;
int a[2*N],ffmax[2*N][2*N][M],ffmin[2*N][2*N][M],sum[2*N];

int main()
{
    n=get(),m=get();
    for(int i=1;i<=n;i++){
        a[i]=get();
        a[i+n]=a[i];
    }
    for(int i=1;i<=n*2;i++){
        sum[i]=sum[i-1]+a[i];
    }
    memset(ffmin,0x3f3f,sizeof(ffmin));
    memset(ffmax,-1,sizeof(ffmax));
    for(int i=1;i<=2*n;i++){
        for(int j=i;j<=2*n;j++){
            ffmax[i][j][1]=((sum[j]-sum[i-1])%mod+mod)%mod;
            ffmin[i][j][1]=((sum[j]-sum[i-1])%mod+mod)%mod;
        }
    }
    for(int i=2;i<=m;i++){
        for(int l=1;l<=n;l++){
            for(int r=l+i-1;r<=l+n-1;r++){
                for(int d=l+i-2;d<=r-1;d++){
                    ffmax[l][r][i]=max(ffmax[l][r][i],ffmax[l][d][i-1]*(((sum[r]-sum[d+1-1])%mod+mod)%mod));
                    ffmin[l][r][i]=min(ffmin[l][r][i],ffmin[l][d][i-1]*(((sum[r]-sum[d+1-1])%mod+mod)%mod));
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        ansmax=max(ansmax,ffmax[i][i+n-1][m]);
        ansmin=min(ansmin,ffmin[i][i+n-1][m]);
    }
    printf("%d\n%d",ansmin,ansmax);
    return 0;
}

 

再见,祝你好运!!

 

posted @ 2022-06-17 14:00  你的小垃圾  阅读(42)  评论(0编辑  收藏  举报