洛谷 P1043 数字游戏

传送门:洛谷 P1043 数字游戏
算法分析:
首先,这张图是一个环的形式,题目大意是要对任意一段求和,故使用前缀和算法,并将数据重复储存来把环破开成链。
其次,这道题用区间DP,以最大值为例:
\(dp[i][j][t]\) 为从 \(i\)\(j\) 中分为 \(t\) 部分所得的最大价值,则
\(dp[i][j][t] = max(dp[i][j][t],dp2[i][k-1][t-1]*(a[j]-a[k-1])\%10)\)
其中 \(t\)\(2\)\(m\)\(i\)\(1\)\(2n\)(环破成链),\(j\)\(i+t-1\)(从 \(i\) 开始的 \(t\) 个数)到 \(2n\)
每次将 \(dp_1\)(求最小值)设为 \(inf\),枚举区间 \(k\),最后枚举开始位,求取 \(n\) 位并分割 \(m\) 次中的最大(小)值。

时间复杂度 \(O(mn^3)\)


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=100,maxM=9,inf=2147483647;
int dp1[maxN+1][maxN+1][maxM+1];
int dp2[maxN+1][maxN+1][maxM+1];
int n,m,a[maxN+1];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[n+i]=a[i];
    }
    n*=2;
    for(int i=2;i<=n;i++)
        a[i]+=a[i-1];
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            dp1[i][j][1]=dp2[i][j][1]=((a[j]-a[i-1])%10+10)%10;
    for(int t=2;t<=m;t++)
        for(int i=1;i<=n;i++)
            for(int j=i+t-1;j<=n;j++)
            {
                dp1[i][j][t]=inf;
                for(int k=i+t-1;k<=j;k++)
                {
                    int temp=((a[j]-a[k-1])%10+10)%10;
                    dp1[i][j][t]=min(dp1[i][j][t],dp1[i][k-1][t-1]*temp);
                    dp2[i][j][t]=max(dp2[i][j][t],dp2[i][k-1][t-1]*temp);
                }
            }
    n/=2;
    int maxT=0,minT=inf;
    for(int i=1;i<=n;i++)
    {
        maxT=max(dp2[i][i+n-1][m],maxT);
        minT=min(dp1[i][i+n-1][m],minT);
    }
    printf("%d\n%d",minT,maxT);
    getchar(); getchar();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ezsyshx/p/10359363.html