1 股神

问题描述:

有股神吗?

有,小赛就是!

经过严密的计算,小赛买了一支股票,他知道从他买股票的那天开始,股票会有以下变化:第一天不变,以后涨一天,跌一天,涨两天,跌一天,涨三天,跌一天...依此类推。

为方便计算,假设每次涨和跌皆为1,股票初始单价也为1,请计算买股票的第n天每股股票值多少钱?

解题思路:

找规律:设 f(n)为第 n 天的股票钱。 由题意知   f(1)=1   f(2)=2     f(3)=1    f(4) =2   f(5)=3  ...  f(6)=2   ...  f(10)=4 .... f(15)=7 ...f(21)=11 ...

标红的是跌的那天股票钱。其实是有规律的。下面来找规律:

我们再定义 g(k)。g(1)=3, g(2)=6, g(3)=10,g(4)=15  ...

再定义u(m)。             u(1)=1,    u(2)=2, u(3)=4,u(4)=7      ...

不难得出  g(k)=3+(k+4)*(k-1)/2  ,      u(m)=1+m*(m-1)/2  。

回归到问题  现在给定 n ,求 f(n)。     我们如果  求出    n1 <= n <n2    其中 n1 和 n2是 n 中  相邻两次的下跌时天数。 即在  n1 至 n2 之间都是上涨的。

 现在关键是求 n1 。  知道 n1 ,则  f(n)=f(n1)+n - n1。  现在问题转为求  n1 和 f(n1)。

如果能得到  g(k)<= n <  g(k+1)   则  n1 = g(k)。 因为   根据前面 g(k)的定义 g(k)就是 下跌时 对应的天数。 

我们知道了 g(k)表达式  不难求出 k。     再回归到 g(k)和 u(k)的定义(u(m)和u(k)意思一样)  , 有 f ( g(k) ) = u (k) 。

所以知道了k 就同时知道了 n1  和 f(n1) 。 问题解决。

现在为了尽量介绍 k 的迭代次数,用下面方法

 (

   g(k)<= n     =》   3+(k+4)*(k-1)/2  <=  n     =》     (k+4)*(k-1)/2 <= n    =》     (k-1)*(k-1)/2 <= n    =》   k<=sqrt(2*n)+1,

  如果 这是 k  的初始值的化  发现程序  输入 n = 9 时  输出  不正确。

  原因是, 这样求出的 初始值K,  有 可能第一次带入  g(k)就有    g(k)>n, 这样是不行的     会出现这种情况  :

       g(k)>  g(k1)  > n 。  跳 出 while 循环后  g(k)g(k2)>  g(k1)  > n  (因为跳出循环前  执行了 k++ )  所以当  k -= 2,其实  k = k1, 

       而我们以为  g(k1)< n  。 所以出现输出错误。 

     出现这种情况的原因是  求 k的初始值时     当(k-1)*(k-1)/2 <= n    求出的k   有可能  (k-1)*(k-1)/2 <= n  <(k+4)*(k-1)/2 。

   如果我们能保证初始 的 k,  使得 (k+4)*(k-1)/2 <  n 。就能避免上述的错误。

 求(k+4)*(k-1)/2 <= n    我们求   (k+4)*(k+4)/2 <= n  的 k值 就能满足  要求。 

 )

下面是代码:

 

 

#include<iostream>
#include <cmath>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        if(n<=0)
            continue;
        else if(n==1){
            cout<<1<<endl;
            continue;
        }
        int k=sqrtf(2*n)-4;  //为了减少迭代次数      
        if(k<0) k=0;
        int m=0;
        while(m<=n){
            m=3+(k+4)*(k-1)/2;
            k++;
        }
        k-=2;
        m=3+(k+4)*(k-1)/2;
        int i=1+k*(k-1)/2;
        i+=n-m;
        cout<<i<<endl;
    }
    return 0;
}

 

这种解法比较复杂 。网上有种 简单的解法

代码思路 如下:

public static int Cal2(int n){
        int i = 0;// i统计遇到了多少次下跌
        int j = 2;// 每次下跌之后上涨的天数,包含已经下跌的那天
        int k = n;
        while (k > j) {
            i += 2;
            k -= j;
            ++j;
        }
        return n - i;
    }

 

 2017-09-14

 

posted @ 2017-09-14 21:50  lqwh  阅读(224)  评论(0编辑  收藏  举报