https://www.luogu.org/problem/show?pid=1043
题目描述
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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,按顺序给出圈中的数字,首尾相接。
输出格式:
输出文件有两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。
输入输出样例
输入样例#1:
4 2 4 3 -1 2
输出样例#1:
7 81
环->破换成链。
f[i][j][k] 表示 在[i,j]区间内 化成 h个部分 的最值
求出前缀和 枚举h,左右端点以及断点-->>f[i][j][h]=(f[i][k-1][h-1]*(sum[j]-sum[k-1])
1 #include <cstdio> 2 3 #define INF (1e7) 4 #define max(a,b) (a>b?a:b) 5 #define min(a,b) (a<b?a:b) 6 7 using namespace std; 8 9 const int N(233); 10 int n,m,num[N],sum[N]; 11 int f_min[N][N][10],f_max[N][N][10],maxn,minn=INF; 12 13 int main() 14 { 15 scanf("%d%d",&n,&m); 16 for(int i=1;i<=n;i++) 17 scanf("%d",num+i),num[i+n]=num[i]; 18 for(int i=1;i<=(n<<1);i++) 19 sum[i]+=sum[i-1]+num[i]; 20 for(int i=1;i<=(n<<1);i++) 21 for(int j=i;j<=(n<<1);j++) 22 for(int k=1;k<=m;k++) 23 { 24 if(k==1) 25 { 26 f_min[i][j][k]=((f_min[i][j-1][k]+num[j])%10+10)%10; 27 f_max[i][j][k]=((f_max[i][j-1][k]+num[j])%10+10)%10; 28 } 29 else f_min[i][j][k]=INF; 30 } 31 for(int h=2;h<=m;h++) 32 for(int i=1;i<=(n<<1);i++) 33 for(int j=h+i-1;j<=(n<<1);j++) 34 for(int k=h+i-1;k<=j;k++) 35 { 36 f_min[i][j][h]=min(f_min[i][j][h],f_min[i][k-1][h-1]*(((sum[j]-sum[k-1])%10+10)%10)); 37 f_max[i][j][h]=max(f_max[i][j][h],f_max[i][k-1][h-1]*(((sum[j]-sum[k-1])%10+10)%10)); 38 } 39 for(int i=1;i<=n;i++) 40 { 41 minn=min(minn,f_min[i][i+n-1][m]); 42 maxn=max(maxn,f_max[i][i+n-1][m]); 43 } 44 printf("%d %d ",minn,maxn); 45 return 0; 46 }