洛谷 P1043 数字游戏

题目传送门

解题思路:

跟石子合并差不多,区间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\n%d",minans,maxans);
35     return 0;
36 }
posted @ 2020-01-20 21:29  Mr^Simon  阅读(135)  评论(0编辑  收藏  举报