题目描述

丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分为m个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数k。游戏的要求是使你所得的k最大或者最小。

例如,对于下面这圈数字(n=4,m=2):

洛谷P1043 数字游戏-LMLPHP

要求最小值时,((2-1) mod 10)×((4+3) mod 10)=1×7=7,要求最大值时,为((2+4+3) mod 10)×(-1 mod 10)=9×9=81。特别值得注意的是,无论是负数还是正数,对10取模的结果均为非负值。

丁丁请你编写程序帮他赢得这个游戏。

输入输出格式

输入格式:

输入文件第一行有两个整数,n(1≤n≤50)和m(1≤m≤9)。以下n行每行有个整数,其绝对值不大于104,按顺序给出圈中的数字,首尾相接。

输出格式:

输出文件有两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。

输入输出样例

输入样例#1: 

4 2
4
3
-1
2
输出样例#1: 

7
81

$DpMin[i][j][k]$表示$i$到$j$中切了$k$次的最小值

$DpMax$表示最大值

转移的时候枚举断点

左右两边相乘

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=;
const int INF=0x7fffff;
inline char nc()
{
static char buf[MAXN],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
char c=nc();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=nc();}
while(c>=''&&c<=''){x=x*+c-'';c=nc();}
return x*f;
}
int DpMin[][][];
int DpMax[][][];
int a[MAXN];
int Query(int a)
{
return ((a%)+)%;
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
int n=read(),m=read();
for(int i=;i<=n;i++) a[i]=read(),a[i+n]=a[i];
for(int i=;i<=*n;i++) a[i]+=a[i-]; for(int l=;l<=*n;l++)
for(int r=l;r<=*n;r++)
DpMin[l][r][]=DpMax[l][r][]=Query(a[r]-a[l-]); for(int i=;i<=m;i++)
for(int l=;l<=*n;l++)
for(int r=l+i-;r<=*n;r++)
DpMin[l][r][i]=INF;
for(int i=;i<=m;i++)//已经切了k次
for(int l=;l<=*n;l++)
for(int r=l+i-;r<=*n;r++)
for(int k=l+i-;k<r;k++)
{
DpMin[l][r][i]=min(DpMin[l][r][i],DpMin[l][k][i-]*Query(a[r]-a[k]));
DpMax[l][r][i]=max(DpMax[l][r][i],DpMax[l][k][i-]*Query(a[r]-a[k]));
}
int AnsMax=,AnsMin=INF;
for(int i=;i<=n;i++)
AnsMax=max(AnsMax,DpMax[i][i+n-][m]),
AnsMin=min(AnsMin,DpMin[i][i+n-][m]);
printf("%d\n%d",AnsMin,AnsMax);
return ;
}
05-28 17:01