为纪念2008年奥运会,邮局发行了N张纪念邮票,面植按编号分别为1分,2分,3分,.....N分.有一个集邮爱好者,由于资金有限,不能买所有的邮票,也不想买邮票号断断续续的,于是,他计划买A分到N分的N-B+1张连续的邮票,且刚好花完M分钱 输入以0 0结束
其中(N,M<=10的9次方)
时间不超过 1 秒钟,
如输入
100 100
0 0输出[9,16]
[18,22]
[100,100]
其中(N,M<=10的9次方)
时间不超过 1 秒钟,
如输入
100 100
0 0输出[9,16]
[18,22]
[100,100]
面值分别为1分,2分,3分,.....N分,那么
买A分到N分的邮票,恐怕选择很有限吧,给定的 M 分钱不太可能刚好花完。
有一个集邮爱好者,由于资金有限,不能买所有的邮票,也不想买邮票号断断续续的,于是,他计划买A分到C分的C-B+1张连续的邮票,且刚好花完M分钱 输入以0 0结束
B是什么东西???
核心算法如下:(凑合用吧)package houlei.test;/**
* 有一个集邮爱好者,由于资金有限,不能买所有的邮票,也不想买邮票号断断续续的,
* 于是,他计划买A分到C分的C-B+1张连续的邮票,且刚好花完M分钱
*
* @author 侯磊
*
*/
public class BuyStamp { public static void main(String[] args) {
//参数 :
//N=共有N张面值连续的邮票。
//M=共有M分钱来购买连续面值的邮票。
final int N=100;
final int M=100;
int col=1;
for(int row = 1;row<=N;row++){
for(;col<=N;col++){
float m = (row+col)*(col-row+1)/2f;
if(m<M)continue;
if(m==M){
System.out.println("["+row+","+col+"]");
continue;
}
if(m>M){
break;
}
}
}
}}
1.很显然,给出的邮票面值,是一个公差为1的等差数列。可得到前n项和的公式,如果row表示首项,col表示末项,m表示前n项和。
则有,(row+col)*(col-row+1)=2*m
2.分析上面的公式,画一个二维矩阵,行号为row,列号为col,我们可以发现一个规律:
A.我们题目当中的情况,只用到了上三角形矩阵中的元素(即以A11和Ann为对称轴,右上方所形成的矩阵),因为,等差数列末项不小于首项。
B.当row不变,m的值随col的增加而增加,
C.当col不变,m的值随row的增加而减小,
D.当row和col同时增加1时,m的值也要增加。
3.分析结束,可以得到以下结论。
A。如果上三角形矩阵中,某一位置对应row、col值,所算得的(row+col)*(col-row+1)>2*m ,则,以该元素为起始点,向右下方画一条平行于对称轴的射线,射线上的元素,他们对应位置的row、col值所算得的(row+col)*(col-row+1)>2*m 依然成立。并且,射线右方的所有元素(行号<=row),他们对应位置的row、col值所算得的(row+col)*(col-row+1)>2*m 也依然成立。
B。上述射线的下方元素,有可能就有我们所求的值(即对应的row和col)。
C。每一个元素,它的下方元素算得的(row+col)*(col-row+1)值要比本身小;右方元素算得的(row+col)*(col-row+1)值要比本身大。
D。我们可以通过阶梯法,去试每一个接近M的位置对应的(row+col)*(col-row+1)值,选出所求的答案。需要说明的事项:
1.算法中用到了乘法和除法运算,这样,变量要转换成浮点数来进行运算。如果“float m = (row+col)*(col-row+1)/2f;”不写最后的那个f,运算的误差会增大。
2.m不使用浮点数,运算误差会增大,使用了以后,判断M与m是否相等,理论上是不能使用“==”的。应该先对m与M的差取绝对值,再判断这个绝对值是否要比一个非常小的正数小(一般好像是10的-9次方)。我为了省事,没加这个判断,这样,误差的范围也会增大。