数字游戏
题目描述
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分为m个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数k。游戏的要求是使你所得的k最大或者最小。
例如,对于下面这圈数字(n=4,m=2):
要求最小值时,((2−1)mod10)×((4+3)mod10)=1×7=7,要求最大值时,为((2+4+3)mod10)×(−1mod10)=9×9=81。特别值得注意的是,无论是负数还是正数,对10取模的结果均为非负值。
丁丁请你编写程序帮他赢得这个游戏。
输入格式
输入文件第一行有两个整数,n(1≤n≤50)和m(1≤m≤9)。以下n行每行有个整数,其绝对值≤10^4,按顺序给出圈中的数字,首尾相接。
输出格式
输出文件有2行,各包含1个非负整数。第1行是你程序得到的最小值,第2行是最大值。
输入输出样例
输入 #1
4 2 4 3 -1 2
输出 #7
81
分析:
这道题有一定难度,我们一步一步分析。
首先对于一个环我们不难想到断环为链,代码也极为简单:
1 for (int i=1;i<=n;i++) a[i]=get(),a[i+n]=a[i];
接下来我们考虑本题的计算,即“特别值得注意的是,无论是负数还是正数,对10取模的结果均为非负值。”那么我们可以用一个函数来计算,代码也不难:
1 int mo(int a){return ((a%10)+10)%10;}
于是最后就只剩下DP的代码了,也就是普通的区间DP,但是注意这题我们需要多加一维,以此来存储当前断了多少段,代码如下(记得先用前缀和存储并且先将n*=2):
1 for (int i=1;i<=n;i++) 2 for (int j=i;j<=n;j++) 3 maxn[i][j][1]=minn[i][j][1]=mo(sum[j]-sum[i-1]); 4 for (int i=2;i<=m;i++) 5 for (int l=1;l<=n;l++) 6 for (int r=l+i-1;r<=n;r++) 7 minn[l][r][i]=oo; 8 for (int i=2;i<=m;i++) 9 for (int l=1;l<=n;l++) 10 for (int r=l+i-1;r<=n;r++) 11 for (int j=l+i-2;j<r;j++){ 12 minn[l][r][i]=min(minn[l][r][i],minn[l][j][i-1]*mo(sum[r]-sum[j])); 13 maxn[l][r][i]=max(maxn[l][r][i],maxn[l][j][i-1]*mo(sum[r]-sum[j])); 14 }
最后统计时一定要注意把n/=2,这样对于每一个起点枚举求最大值和最小值即可,代码如下:
1 for (int i=1;i<=n/2;i++){ 2 ansmax=max(ansmax,maxn[i][i+n/2-1][m]); 3 ansmin=min(ansmin,minn[i][i+n/2-1][m]); 4 }
那么最后就做完这题了,其实这题真不太好做,而且思路也很妙。(这题我花了2个小时啊啊啊啊)
CODE:
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 const int M=100005; 8 const int N=105; 9 const int oo=1<<20; 10 int n,m; 11 int a[M],sum[M]; 12 int maxn[N][N][N],minn[N][N][N]; 13 int ansmax,ansmin=oo; 14 int get(){ 15 int res=0,f=1; 16 char c=getchar(); 17 while (c>'9'||c<'0') { 18 if (c=='-') f=-1; 19 c=getchar(); 20 } 21 while (c<='9'&&c>='0'){ 22 res=(res<<3)+(res<<1)+c-'0'; 23 c=getchar(); 24 } 25 return res*f; 26 } 27 int mo(int a){return ((a%10)+10)%10;} 28 int main(){ 29 freopen("a.in","r",stdin); 30 freopen("a.out","w",stdout); 31 n=get(),m=get(); 32 for (int i=1;i<=n;i++) a[i]=get(),a[i+n]=a[i]; 33 n*=2; 34 for (int i=1;i<=n;i++) sum[i]=a[i]+sum[i-1]; 35 for (int i=1;i<=n;i++) 36 for (int j=i;j<=n;j++) 37 maxn[i][j][1]=minn[i][j][1]=mo(sum[j]-sum[i-1]); 38 for (int i=2;i<=m;i++) 39 for (int l=1;l<=n;l++) 40 for (int r=l+i-1;r<=n;r++) 41 minn[l][r][i]=oo; 42 for (int i=2;i<=m;i++) 43 for (int l=1;l<=n;l++) 44 for (int r=l+i-1;r<=n;r++) 45 for (int j=l+i-2;j<r;j++){ 46 minn[l][r][i]=min(minn[l][r][i],minn[l][j][i-1]*mo(sum[r]-sum[j])); 47 maxn[l][r][i]=max(maxn[l][r][i],maxn[l][j][i-1]*mo(sum[r]-sum[j])); 48 } 49 for (int i=1;i<=n/2;i++){ 50 ansmax=max(ansmax,maxn[i][i+n/2-1][m]); 51 ansmin=min(ansmin,minn[i][i+n/2-1][m]); 52 } 53 cout<<ansmin<<endl<<ansmax<<endl; 54 return 0; 55 }