题目描述
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分为m个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数k。游戏的要求是使你所得的k最大或者最小。
例如,对于下面这圈数字(n=4,m=2)
当要求最小值时,((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,按顺序给出圈中的数字,首尾相接。
输出
有两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。
样例
样例输入
4 2
4
3
-1
2
样例输出
7
81
分析
n个数围成一圈,按顺序分成m部分,每部分的数字求和并对10取模再相乘,求最终结果的最大值和最小值
首先将环转换成链
先考虑最小值
f[l][r][k]
表示 将区间[l,r]分成k段的最小值
根据第k段进行转移,分为 [l,p] 和 [p + 1,r] 两段
f
[
l
]
[
r
]
[
k
]
=
m
i
n
(
f
[
l
]
[
r
]
[
k
]
,
f
[
l
]
[
p
]
[
k
−
1
]
∗
c
a
l
c
(
p
+
1
,
r
)
)
;
f[l][r][k] = min(f[l][r][k],f[l][p][k - 1] * calc(p + 1,r));
f[l][r][k]=min(f[l][r][k],f[l][p][k−1]∗calc(p+1,r));
最大值同理
代码
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100 + 10,M = 9 + 10,INF = 0x3f3f3f3f;
int n,m;
int a[N],s[N];
int f[N][N][M],g[N][N][M];
int calc(int l,int r){
int tmp = s[r] - s[l - 1];
return (tmp % 10 + 10) % 10;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i++){
cin >> a[i];
a[i + n] = a[i];
}
for(int i = 1;i <= 2 * n;i++) s[i] = s[i - 1] + a[i];
memset(f,0x3f,sizeof f);
memset(g,-0x3f,sizeof g);
for(int len = 1;len <= n;len++)
for(int i = 1;i + len - 1 <= 2 * n;i++){
int l = i,r = i + len - 1;
f[l][r][1] = g[l][r][1] = calc(l,r);
for(int k = 2;k <= m;k++)
for(int p = l + k - 2;p <= r - 1;p++){
f[l][r][k] = min(f[l][r][k],f[l][p][k - 1] * calc(p + 1,r));
g[l][r][k] = max(g[l][r][k],g[l][p][k - 1] * calc(p + 1,r));
}
}
int mn = INF,mx = -INF;
for(int i = 1;i <= n;i++){
mn = min(mn,f[i][i + n - 1][m]);
mx = max(mx,g[i][i + n - 1][m]);
}
cout << mn << '\n' << mx;
return 0;
}