您的位置:首页 > 其它

1085 数字游戏

2016-07-28 19:43 211 查看

1085 数字游戏

2003年NOIP全国联赛普及组

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 黄金 Gold

题解

题目描述 Description

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

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

2

4 -1

3

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

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

4 2

4

3

-1

2

样例输出 Sample Output

7

81

数据范围及提示 Data Size & Hint

en

分类标签 Tags 点此展开

划分型DP 动态规划 环型DP NOIP全国联赛普及组 大陆地区 2003年

划分dp

把环变链(读入4 3 -1 2变成4 3 -1 2 4 3 -1 2)

设dp[i][j][k]为把i~j分成k份,各部分内的数字相加,相加所得的k个结果对10取模后再相乘,最终得到的一个数,这个数的最大或最小值。

dp[i][j][k]=max/min{dp[i][p][k-1]+func(p+1,j)}

i+k-2<=p<=j-1  func(i,j)=(sum(i,j)%10+10)%10

(注意有负数取余,这样写:(x%10+10)%10 )

边界:dp[i][j][1]=func(i,j)

答案:max/min(dp[i][i+n-1][m]) i=1 to n+1

AC代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define N 80
#define ll long long
ll f

,g

,a
,s
,n,m,emax,emin=0x7fffffff;
ll get(ll x){
return x>=0?x%10:10-abs(x)%10;
}
int main(){
freopen("sh.txt","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
for(int i=1;i<=n<<1;i++) s[i]=get(s[i-1]+a[i]);
for(int i=0;i<n;i++){
memset(f,0,sizeof f);
memset(g,1,sizeof g);//取较大值 注意数据可能导致上溢
for(int j=1;j<=n;j++) f[j][1]=g[j][1]=get(s[j+i]-s[i]);
for(int j=2;j<=m;j++){
for(int k=j;k<=n;k++){
for(int l=1;l<k;l++){
f[k][j]=max(f[k][j],f[l][j-1]*(get(s[k+i]-s[l+i])));
g[k][j]=min(g[k][j],g[l][j-1]*(get(s[k+i]-s[l+i])));
}
}
}
emax=max(emax,f
[m]);
emin=min(emin,g
[m]);
}
cout<<emin<<endl<<emax<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: