题目传送门
解题思路:
跟石子合并差不多,区间DP(环形),用f[i][j][s]表示从i到j分成s段所能获得的最大答案,枚举断点k,则f[i][j][s] = min(f[i][j][s],f[i][k][s-1] * 代价),最小值反之.
ps:区间和用前缀和维护.
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,m,sum[120],f[200][200][10],f2[200][200][10],a[52]; 8 9 int main() { 10 scanf("%d%d",&n,&m); 11 for(int i = 1;i <= n; i++) { 12 scanf("%d",&a[i]); 13 sum[i] = sum[i-1] + a[i]; 14 } 15 memset(f,0x3f3f,sizeof(f)); 16 for(int i = n + 1;i <= 2 * n; i++) 17 sum[i] = sum[i-n] + sum[n]; 18 for(int i = 1;i <= 2 * n; i++) 19 for(int j = i;j <= 2 * n; j++) 20 f[i][j][1] = f2[i][j][1] = ((sum[j] - sum[i-1]) % 10 + 10) % 10; 21 for(int len = 0;len < n; len++) 22 for(int i = 1,j = i + len;j <= 2 * n; i++,j++) 23 for(int s = 2;s <= m; s++) 24 for(int k = i + s - 1;k < j; k++) { 25 f[i][j][s] = min(f[i][j][s],f[i][k][s-1] * (((sum[j] - sum[k]) % 10 + 10) % 10)); 26 f2[i][j][s] = max(f2[i][j][s],f2[i][k][s-1] * (((sum[j] - sum[k]) % 10 + 10) % 10)); 27 } 28 int maxans = 0; 29 int minans = 0x3f3f3f3f; 30 for(int i = 1;i <= 2 * n; i++) { 31 maxans = max(maxans,f2[i][i+n-1][m]); 32 minans = min(minans,f[i][i+n-1][m]); 33 } 34 printf("%d %d",minans,maxans); 35 return 0; 36 }