题解 - 数字游戏

题目描述

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

输出

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

样例

样例输入

4 2
4
3
-1
2

样例输出

7
81

分析

n个数围成一圈,按顺序分成m部分,每部分的数字求和并对10取模再相乘,求最终结果的最大值和最小值

首先将环转换成链

先考虑最小值

f[l][r][k] 表示 将区间[l,r]分成k段的最小值

根据第k段进行转移,分为 [l,p] 和 [p + 1,r] 两段
f [ l ] [ r ] [ k ] = m i n ( f [ l ] [ r ] [ k ] , f [ l ] [ p ] [ k − 1 ] ∗ c a l c ( p + 1 , r ) ) ; f[l][r][k] = min(f[l][r][k],f[l][p][k - 1] * calc(p + 1,r)); f[l][r][k]=min(f[l][r][k],f[l][p][k1]calc(p+1,r));
最大值同理

代码

#pragma GCC optimize(2)
  
#include<bits/stdc++.h>
   
using namespace std;
   
typedef long long LL;
   
const int N = 100 + 10,M = 9 + 10,INF = 0x3f3f3f3f;
 
int n,m;
int a[N],s[N];
int f[N][N][M],g[N][N][M];
 
int calc(int l,int r){
    int tmp = s[r] - s[l - 1];
    return (tmp % 10 + 10) % 10;
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
 
    cin >> n >> m;
    for(int i = 1;i <= n;i++){
        cin >> a[i];
        a[i + n] = a[i];
    }
 
    for(int i = 1;i <= 2 * n;i++) s[i] = s[i - 1] + a[i];
 
    memset(f,0x3f,sizeof f);
    memset(g,-0x3f,sizeof g);
 
    for(int len = 1;len <= n;len++)
        for(int i = 1;i + len - 1 <= 2 * n;i++){
            int l = i,r = i + len - 1;
            f[l][r][1] = g[l][r][1] = calc(l,r);
            for(int k = 2;k <= m;k++)
                for(int p = l + k - 2;p <= r - 1;p++){
                    f[l][r][k] = min(f[l][r][k],f[l][p][k - 1] * calc(p + 1,r));
                    g[l][r][k] = max(g[l][r][k],g[l][p][k - 1] * calc(p + 1,r));
                }
        }
     
    int mn = INF,mx = -INF;
    for(int i = 1;i <= n;i++){
        mn = min(mn,f[i][i + n - 1][m]);
        mx = max(mx,g[i][i + n - 1][m]);
    }
 
    cout << mn << '\n' << mx;
 
    return 0;
}
  • 32
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值