[题解] 数字游戏

“The Game Is On.”——Sherlock·Holmes

【问题描述】

游戏是这样的:在你面前有一圈整数(一共N个),你要按顺序将其分为M个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数k。游戏的要求是使你所得的k最大或者最小。例如,对于下面这圈数字(N=4,M=2):
        
  ◆最小值:((2-1) mod 10)×((3+4) mod 10)=1×7=7。
  ◆最大值:(-1 mod 10)×((3+4+2) mod 10) =9×9=81。
这里写图片描述
  特别值得注意的是,无论是负数还是正数,对10取模的结果均为非负值。请你编写程序帮他赢得这个游戏。

【输入格式】

第一行有两个整数,N(1≤N≤50)和M(1≤M≤9)。
  接下来的N行,每行一个整数,其绝对值不大于10000,按顺序给出圈中的数字,首尾相接。

【输出格式】

两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。

【输入样例】

4 2
2
-1
3
4

【输出样例】

7
81

【数据范围】

1≤N≤50 1≤M≤9


#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
#define MAXN 1000000000
using namespace std;

int N,M,ansmax=-MAXN,ansmin=MAXN;
int num[55],prefix[55]={0};
int f_min[55][15]={0},f_max[55][15]={0};

void prefix_sum(){
	for(int i=1;i<=N;i++){
		prefix[i]=prefix[i-1]+num[i];
	}
}//用前缀和的思想,算出分一组时的和 

void roll(){
	for(int i=1;i<=N;i++){
		num[i-1]=num[i];
	}
	num[N]=num[0];
} 

int main(){
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++){
		scanf("%d",&num[i]);
	}
	
	for(int cnt=1;cnt<=N;cnt++){
	//N种排序方式都要算 
	
		prefix_sum();
		
		for(int i=1;i<=N;i++){
			f_min[i][1]=(prefix[i]%10+10)%10;
			f_max[i][1]=(prefix[i]%10+10)%10;
		}
		//初始化分一组的情况
		 
		//f[n][m]:n个元素分成m组,和的最小/大值(n>=m)
		for(int m=2;m<=M;m++){
			for(int n=m;n<=N;n++){
				f_min[n][m]=MAXN;
				f_max[n][m]=-MAXN;
				for(int i=m-1;i<=n-1;i++){
					f_min[n][m]=min(f_min[n][m],f_min[i][m-1]*(((prefix[n]-prefix[i])%10+10)%10));
					f_max[n][m]=max(f_max[n][m],f_max[i][m-1]*(((prefix[n]-prefix[i])%10+10)%10));
				}
			}
		}
		
		ansmax=max(ansmax,f_max[N][M]);
		ansmin=min(ansmin,f_min[N][M]);
		//多组ans,求最值 
		
		roll();
		//环状数组,每算出一次答案都要向前滚动一位
	}
	
	printf("%d\n%d",ansmin,ansmax);
	return 0;
}

[转载请标明出处 , 谢谢]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值