noip2003普及组-数字游戏

来源:互联网 发布:金鼎智赢交易软件 编辑:程序博客网 时间:2024/06/05 17:26

题目描述

丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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 243-12
输出样例#1:
781













【题解】这题考的是区间dp(+破环成链)。算是学习了,刷真题果然学到不少。

#include<cstdio>#include<cstring>#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))const int maxn=60*2,maxm=15;//破环成链,数组大小翻倍 #define INF 0x3f3f3f3fint main(){int n,m,v[maxn];int f[maxn][maxn][maxm]={0},g[maxn][maxn][maxm];//f表示最大值,g表示最小值 int total[maxn][maxn]={0},sum[maxn]={0};//total为各个区间mod10的结果,sum是前缀和 int Maxans=-INF,Minans=INF;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&v[i]);v[i+n]=v[i];}n<<=1;//破环成链memset(g,INF,sizeof(g));for(int i=1;i<=n;i++)sum[i]=sum[i-1]+v[i];//求出区间和 for(int i=1;i<=n;i++)for(int j=i;j<=n;j++)f[i][j][1]=g[i][j][1]=total[i][j]=((sum[j]-sum[i-1])%10+10)%10;//方便操作,求出各个区间内的数mod 10//a mod b≡((a mod b)+10)(mod 10) a<0,b>0for(int l=2;l<=m;l++)for(int j=1;j<=n;j++)for(int i=1;i<=j;i++)for(int k=i;k<j;k++){f[i][j][l]=max(f[i][j][l],f[i][k][l-1]*total[k+1][j]);if(g[i][k][l-1]<INF)g[i][j][l]=min(g[i][j][l],g[i][k][l-1]*total[k+1][j]);//注意溢出 }n=n>>1;for(int i=1;i<=n;i++){Maxans=max(Maxans,f[i][i+n-1][m]);Minans=min(Minans,g[i][i+n-1][m]);}printf("%d\n%d\n",Minans,Maxans);return 0;}