传送门:洛谷 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;
}
原文:https://www.cnblogs.com/ezsyshx/p/10359363.html