本题应该用动态规划才方便,但这里先介绍一种深搜的用法。
既然他将一个圆形的分成几部分,为了表示这个圆形我们可以开一个二倍的数组去保存两个相同的序列,这样就可以将首尾给衔接上。
那么如何表示圆形序列的分隔呢?在这里可以使用一个now表示当前部分的开头坐标,然后向后去枚举这个部分的末尾下标,要注意这个末尾下标必须给后面的部分留出足够的位置所以是i<=now+n-2-(m-depth)。那么递归这个每一个部分就可以了,但是直接暴力的话会超时所以使用一个结果性的剪枝:当前的数,还比最小值要大并且,加上接下来全为的最大值比最大值要小的话,直接剪枝。
此外在这里面还是用sum数组保存前缀和来快速算出区间里面数的总和。
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 50*2+10; const int p = 1000000; int a[maxn]; int sum[maxn]; int n, m, mod = 10; int min_ans = LONG_LONG_MAX, max_ans = LONG_LONG_MIN; int max_val[10] = {9, 81, 729, 6561, 59049, 531441, 4782969, 43046721, 387420489, 3486784401}; void DFS(int depth, int now, int start, int num) { if (depth==m) { min_ans = min(min_ans, num*((sum[start+n-1]-sum[now-1]+p)%mod)); max_ans = max(max_ans, num*((sum[start+n-1]-sum[now-1]+p)%mod)); return ; } //如果当前的数,还比最小值要大并且,加上接下来全为的最大值比最大值要小的话,直接剪枝。 if (num>=min_ans&&num*max_val[m-now]<=max_ans) { return ; } for (int i=now;i<=now+n-2-(m-depth);i++) { DFS(depth+1, i+1, start, num*((sum[i]-sum[now-1]+p)%mod)); } } signed main() { cin>>n>>m; int sum_val = 0; for (int i=1;i<=n;i++) { cin>>a[i]; a[i+n] = a[i]; sum_val += a[i]; } for (int i=1;i<=n*2;i++) { //计算前缀和方便计算总和。 sum[i] = sum[i-1]+a[i]; } //遍历从哪开始。 for (int i=1;i<=n;i++) { //记录遍历了几个,开始于哪里,一开始是哪里,累计的数是多少。 DFS(1, i, i, 1); } cout<<min_ans<<endl; cout<<max_ans; return 0; }动态规划的做法:
动态规划可以建立一个三维度的数组f[i][j][k]。其中i和j代表这个区间的左边和右边下标。k代表要将这个区间分成几部分。
那么在给定区间[i,j]里面分成3部分能够得到的最大值不应该是分成两部分的区间值加上剩下的区间值吗,也就是说可以枚举这个小区间里面的值以及他相应的两部分的区间值。取其中最大的就是结果了。分成4,5,6部分也会同样的步骤。