丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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取模的结果均为非负值。
丁丁请你编写程序帮他赢得这个游戏。
输入文件第一行有两个整数,n(1≤n≤50)和m(1≤m≤9)。以下n行每行有个整数,其绝对值不大于104,按顺序给出圈中的数字,首尾相接。
输出文件有两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。
4 2
4
3
-1
2
7
81
en
分类标签 Tags 点此展开
划分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[N][N],g[N][N],a[N],s[N],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[n][m]); emin=min(emin,g[n][m]); } cout<<emin<<endl<<emax<<endl; return 0; }