数字游戏

数字游戏

Time Limit: 1 Sec  Memory Limit: 128 MB

丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分为m个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数k。游戏的要求是使你所得的k最大或者最小。

例如,对于下面这圈数字(n=4m=2):

当要求最小值时,((2-1) mod 10)×((4+3) mod 10)=1×7=7,要求最大值时,为((2+4+3) mod 10)×(-1 mod 10)=9×9=81。特别值得注意的是,无论是负数还是正数,对10取模的结果均为非负值。

丁丁请你编写程序帮他赢得这个游戏

Input

输入文件第一行有两个整数,n1n50)和m1m9)。以下n行每行有个整数,其绝对值不大于104,按顺序给出圈中的数字,首尾相接。

Output

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

Sample Input

4 2
4
3
-1
2

Sample Output

7
81

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define maxn 60

using namespace std;
const int inf=-1u>>1;
int num[maxn],sum[2*maxn]; //前i项和
int ans1[maxn][maxn],ans2[maxn][maxn];  //ans1表示最小值,ans2表示最大值
int mod(int n)
{
    return n>0?n%10:n%10+10;
}
int main()
{
    int n,m;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(cin>>n>>m){
        sum[0]=0;
        int Max=0,Min=inf;
       for(int i=1;i<=n;i++){
            cin>>num[i];
            sum[i]=sum[i-1]+num[i];
       }
       for(int i=1;i<=n;i++) sum[n+i]=sum[n+i-1]+num[i];
       //for(int i=1;i<=2*n;i++)cout<<sum[i]<<" ";cout<<endl;
       for(int i=1;i<=n;i++){  //枚举起点
            for(int j=1;j<=n;j++)
            for(int k=1;k<=m;k++){
                ans1[j][k]=inf;
                ans2[j][k]=0;
            }
            for(int j=1;j<=n;j++)
                ans1[j][1]=ans2[j][1]=mod(sum[i+j-1]-sum[i-1]);
            for(int j=2;j<=n;j++) //从i起前j项
                for(int k=2;k<=m;k++)  //堆数
                    for(int kk=1;kk<j;kk++){  //从i起前kk项
                        if(ans1[kk][k-1]!=inf)
                            ans1[j][k]=min(ans1[j][k],ans1[kk][k-1]*mod(sum[i+j-1]-sum[i+kk-1]));
                            ans2[j][k]=max(ans2[j][k],ans2[kk][k-1]*mod(sum[i+j-1]-sum[i+kk-1]));
                            //cout<<"--"<<ans1[j][k]<<"--";
                           // cout<<"--"<<ans2[j][k]<<"--";
                    }
            Max=max(Max,ans2[n][m]);
            Min=min(Min,ans1[n][m]);
            //cout<<Min<<"**"<<Max<<endl;
        }
        cout<<Min<<endl<<Max<<endl;
        cout<<Min<<endl<<Max<<endl;
        for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)
			cout<<ans1[i][j]<<" ";
			cout<<endl;
        }
    }
	return 0;
}

注:本题也是环形dp。复杂度O(m*n^3).枚举起点,前j项划分成k堆,可以转换成子问题前kk项划分成k-1堆和mod sum(kk+1->j)。初始条件ans1[j][1]=ans2[j][1]=mod(sum[i+j-1]-sum[i-1]);不要忘了,Max和Min的初值0和inf。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值