洛谷1043 数字游戏
本题地址: http://www.luogu.org/problem/show?pid=1043
题目描述
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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,按顺序给出圈中的数字,首尾相接。
输出格式:
输出文件有两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。
输入输出样例
输入样例#1:
4 2
4
3
-1
2
输出样例#1:
7
81
【思路】
环形DP + 划分型DP。
题目的特殊性在于它是一个环,我们已经处理过环形DP的问题了,把环拆成一条链就可以转化为一个线性的划分DP。
注意:将环形DP拆开并且将拆开的点视为第一段与最后一段的相接处,而不是考虑拆开后的最后一段是否与第一段为同一段。
将元素重复一遍得长度N的链,枚举起点,对于每个起点求解长度为n划分数为k的最大最小划分,比较得出答案。
注意:dg的初始化为d[0][0]=g[0[0]=1;如果为d[1][1]=g[1][1]=a[s+1]则a值可能为负就出现了不合法的情况。
【代码】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 5 using namespace std; 6 7 const int maxn = 100+5; 8 const int INF=421075225; 9 10 int d[maxn][maxn],g[maxn][maxn]; 11 int sum[maxn],a[maxn],S[maxn][maxn]; 12 int n,N,m,ans_min=1<<30,ans_max; 13 14 inline int calc(int i,int j) { 15 int &ans=S[i][j]; //记忆化 16 if(ans!=0) return ans; 17 18 ans=sum[j]-sum[i]; 19 ans%=10; 20 while(ans<0) ans+=10; 21 return ans; 22 } 23 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 FOR(i,1,n) { 28 scanf("%d",&a[i]); 29 a[i+n]=a[i]; 30 } 31 N=2*n-1; 32 FOR(i,1,N) sum[i]=sum[i-1]+a[i] ; 33 34 FOR(s,1,N-n) 35 { 36 memset(d,0,sizeof(d)); 37 memset(g,25,sizeof(g)); 38 d[0][0]=g[0][0]=1; //注意边界 39 FOR(i,1,n) 40 FOR(j,1,min(i,m)) 41 FOR(k,j-1,i-1) 42 { 43 d[i][j]=max(d[i][j],d[k][j-1]*calc(s+k,s+i)); //sum{k+1,i} 44 if(g[k][j-1]<INF) 45 g[i][j]=min(g[i][j],g[k][j-1]*calc(s+k,s+i)); //防止越界 46 } 47 ans_min=min(ans_min,g[n][m]); 48 ans_max=max(ans_max,d[n][m]); 49 } 50 printf("%d\n%d",ans_min,ans_max); 51 return 0; 52 }
原文:http://www.cnblogs.com/lidaxin/p/4898919.html