【解题报告】洛谷P1043 数字游戏
题目链接
https://www.luogu.com.cn/problem/P1043
思路
动态规划,类似于能量项链和石子合并之类的
首先这是一个环,我们用常见的破环成链的技巧——开双倍数组来做
然后我们设置状态 f [ i ] [ j ] f[i][j] f [ i ] [ j ] 表示前 i i i 个数字分成 j j j 个部分可以得到的最小值是多少
则有
f [ i ] [ j ] = m i n { f [ i − k ] [ j − 1 ] × s [ i − k + 1 ] [ i ] } , 0 ≤ k ≤ i
f[i][j]=min\{f[i-k][j-1]\times s[i-k+1][i] \},0 \le k \le i
f [ i ] [ j ] = m i n { f [ i − k ] [ j − 1 ] × s [ i − k + 1 ] [ i ] } , 0 ≤ k ≤ i
同理,我们可以设 g [ i ] [ j ] g[i][j] g [ i ] [ j ] 表示上述的最大值
g [ i ] [ j ] = m i n { g [ i − k ] [ j − 1 ] × s [ i − k + 1 ] [ i ] } , 0 ≤ k ≤ i
g[i][j]=min\{g[i-k][j-1]\times s[i-k+1][i] \},0 \le k \le i
g [ i ] [ j ] = m i n { g [ i − k ] [ j − 1 ] × s [ i − k + 1 ] [ i ] } , 0 ≤ k ≤ i
但是有一个小细节要处理一下
我们在模的时候负数模一个数字还是负数
但是根据题目描述,它要变成正数
所以我们的对于小于0的加一个10就好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #define int long long using namespace std;const int maxn=105 ;int n,m;int a[maxn];int s[maxn][maxn],f[maxn][maxn],g[maxn][maxn];int minn=1e9 ,maxx=-1e9 ;signed main () { cin>>n>>m; for (int i=1 ;i<=n;i++) { cin>>a[i]; a[i+n]=a[i]; } for (int x=0 ;x<=n;x++) { for (int i=x+1 ;i<=x+n;i++) { for (int j=i;j<=x+n;j++) s[i][j]=s[i][j-1 ]+a[j]; } for (int i=x+1 ;i<=x+n;i++) { for (int j=i;j<=x+n;j++) { s[i][j]%=10 ; if (s[i][j]<0 ) s[i][j]+=10 ; } } for (int i=x+1 ;i<=x+n;i++) { for (int j=1 ;j<=m;j++) { f[i][j]=1e9 ; g[i][j]=-1e9 ; } } for (int i=x+1 ;i<=x+n;i++) f[i][0 ]=g[i][0 ]=s[x+1 ][i]; for (int j=1 ;j<=m;j++) { for (int i=j+1 +x;i<=n+x;i++) { for (int k=x+1 ;k<i;k++) { f[i][j]=min (f[i][j],f[k][j-1 ]*s[k+1 ][i]); g[i][j]=max (g[i][j],g[k][j-1 ]*s[k+1 ][i]); } } } maxx=max (maxx,g[x+n][m-1 ]); minn=min (minn,f[x+n][m-1 ]); } cout<<minn<<'\n' <<maxx<<'\n' ; return 0 ; }