【划分型DP】数字游戏
来源:互联网 发布:重工刺绣衣服知乎 编辑:程序博客网 时间:2024/06/05 19:10
在cv上看到一个题解思路清晰,特地搬来这里存一下。
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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
由于是环,需要断环成链。采用序列倍增的方法,即原序列是1 2 3,新序列是1 2 3 1 2 3,枚举dp起点。
O(N^2)预处理,求出第i到j之间数字和对10求余的结果。
注意:正确的求余方法是((n%10)+10)%10!
枚举起点s,前i个数分成j组,其中最后一组含有第k+1到i的数字
状态转移方程:
d[i][j]=min(d[i][j],d[k][j-1]*SumMod10[s+k+1][s+i]);
p[i][j]=max(p[i][j],p[k][j-1]*SumMod10[s+k+1][s+i]);
(0<=s<N;1<=i<=N;1<=j<=min(i,M);j-1<=k<=i-1)
注意:当M=1是,只有一种划分方案,无需状态转移,否则会得出错误的答案(这里卡了好久)!
最后注意一下初始化条件,d[][]=INF,p[][]=0,d[0][0]=p[0][0]=1.
#include<iostream>#include<cstring>#include<climits>#define MAXN 53#define MAXM 12#define INF 1000000using namespace std;int N,M;int n[MAXN*2];int SumMod10[MAXN*2][MAXN*2];int d[MAXN][MAXM];int p[MAXN][MAXM];int MIN=INT_MAX;int MAX=INT_MIN;int main(){ cin>>N>>M; for(int i=1;i<=N;i++) { cin>>n[i]; n[i+N]=n[i]; } for(int i=1;i<=N*2;i++) { SumMod10[i][i]=n[i]; for(int j=i+1;j<=N*2;j++) SumMod10[i][j]=SumMod10[i][j-1]+n[j]; } for(int i=1;i<=N*2;i++) for(int j=i;j<=N*2;j++) { SumMod10[i][j]=((SumMod10[i][j]%10)+10)%10; } if(M==1) { MIN=MAX=SumMod10[1][N]; } else for(int s=0;s<N;s++) { for(int i=0;i<=N;i++) { for(int j=0;j<=M;j++) { d[i][j]=INF; p[i][j]=0; } } d[0][0]=p[0][0]=1; for(int i=1;i<=N;i++) { for(int j=1;j<=min(i,M);j++) { for(int k=j-1;k<=i-1;k++) { d[i][j]=min(d[i][j],d[k][j-1]*SumMod10[s+k+1][s+i]); p[i][j]=max(p[i][j],p[k][j-1]*SumMod10[s+k+1][s+i]); } } } MIN=min(MIN,d[N][M]); MAX=max(MAX,p[N][M]); } cout<<MIN<<endl<<MAX<<endl; return 0;}
划分型DP需要注意的地方
若dp[i][j]表示为前i个分成j份时:
1.要考虑dp[0][0]=1;
2.k=1时无需状态转移,表示只有一种划分方案,需要if语句提前处理边界;
3.预处理时dp[][]=INF.
4.模板(答案为dp[N][M]时)
for(int i=1;i<=N;i++) for(int j=1;j<=min(i,M);j++) for(int k=j-1;k<=i-1;k++) d[i][j]=min(d[i][j],d[k][j-1](?)f(x));
- 【划分型DP】数字游戏
- wikioi1085 - 数字游戏(区间DP或者划分DP)
- 【划分型DP】整数划分
- 数字游戏 (dp)
- [DP]数字游戏
- 划分型DP
- 划分型循环DP
- 划分型DP相关
- 划分型dp
- nefu1018数字游戏二【DP】
- 【划分型DP】数的划分
- 【划分型DP】乘积最大
- SOJ2113: 数字游戏题解动态规划DP
- vijos 1218 数字游戏(环形dp)
- 【概率DP】AHU-600 数字游戏
- soj 2113 数字游戏(环形DP)
- wikioi1039数的划分(划分型dp)
- CODEVS 1039 数的划分(划分型DP)
- python 与 c/c++之间的互相调用
- Oracle中%TYPE和%ROWTYPE说明
- 详细分析make uboot 最后的编译链接的具体执行过程
- C++ 高精度乘法
- 比较有用的网站
- 【划分型DP】数字游戏
- 2014-10-17-State状态
- Hibernate基础教程的Demo代码下载
- Android多媒体之AMR
- HDU 1232 畅通工程
- 取出NSString当中的单个字符
- 中软Java学习8月10日笔记
- JMM内存可见性与顺序一致性模型
- spring+jersery集成注意问题