您的位置:首页 > 其它

[Noip2003 PJ] 数字游戏

2018-03-05 17:00 211 查看

Description & Range

丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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取模的结果均为非负值。

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

Input

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

Output

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

Solution

啊这道题好有水平=.=

第一眼看到这题以为是和石子合并一样水的题,但是蛮多细节要注意的(我也是看题解才知道)

定义 f[0/1][i][j][k] 表示左端点在 i,右端点在 j,分成了 k 个部分的最大/最小乘积

最开始做这题开了五层循环,内层枚举了一下断点和断点两侧分别分成了多少个部分...

后来(抄题解)发现了其实不用枚举两侧分成了多少个部分,因为这会被之前或之后的循环枚举到,打个比方:如果枚举到了左端点是 i,右端点是 j,断点是 k,左边分成了p 个部分,右边分成了 q 个部分。                                                                                                   

先明确一下,在合并时,我们只是关注 k+1~j 的前缀和再乘上左边已经乘好的部分, 即 f[i][j][p+q]=max{f[i][j][p+q-1]*(qzh[j]-qzh[k])}  所以是不用管右边分成了几个部分的,直接假设右边分成了一个部分,然后用左边的区间去“吃”右边的区间就好。

Code

// By YoungNeal
#include<cstdio>
#include<iostream>
using namespace std;

int n,m;
int qzh[105];
int val[105];
int f[2][105][105][15];

int mod(int x){
return (x%10+10)%10;
}

signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&val[i]),val[i+n]=val[i];
for(int i=1;i<=(n<<1);i++) qzh[i]=qzh[i-1]+val[i];
for(int i=1;i<=(n<<1);i++){
for(int j=i;j<=(n<<1);j++)
f[0][i][j][1]=f[1][i][j][1]=mod(qzh[j]-qzh[i-1]);
}
/*愚蠢的五层循环
  for(int len=2;len<=(n<<1);len++){ for(int i=1;i<=(n<<1);i++){ int j=i+len-1; if(j>(n<<1)) break; for(int p=i;p<=j;p++){ for(int k=1;k<=min(m,j-i+1);k++){ for(int q=1;q<k;q++){ if(q<=p-i+1&&k-q<=j-p) f[i][j][k]=max(f[i][j][k],f[i]

[q]+f[p+1][j][k-q]+(qzh[p]-qzh[i-1])*(qzh[j]-qzh[p])); } } } } }*/ for(int i=2;i<=m;i++){ for(int l=1;l<=(n<<1);l++){ for(int r=l+i-1;r<=l+n-1;r++){ //f[l][r][i] f[1][l][r][i]=0x3f3f3f3f; for(int k=l+i-2;k<r;k++){ //k不能=r! f[0][l][r][i]=max(f[0][l][r][i],f[0][l][k][i-1]*mod(qzh[r]-qzh[k])); f[1][l][r][i]=min(f[1][l][r][i],f[1][l][k][i-1]*mod(qzh[r]-qzh[k])); } } } } int maxn=0,minn=0x3f3f3f3f; for(int i=1;i<=n;i++) maxn=max(maxn,f[0][i][i+n-1][m]),minn=min(minn,f[1][i][i+n-1][m]); printf("%d\n%d",minn,maxn); return 0; }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: