• 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

  • 相关阅读:
    Winform中用了皮肤控件之后,报错:容量超出了最大容量 参数名:capacity
    C# 生成二维码
    T-sql语句修改数据库逻辑名、数据库名、物理名
    ASP.NET MVC中使用jQuery时的浏览器缓存问题
    关于asp.net页面缓存
    关于VS 工具箱灰色,不可用的解决方案
    Android
    如何让一个DIV水平,垂直方向都居中于浏览器?
    cookie.setPath()的用法
    CSS选择器
  • 原文地址:https://www.cnblogs.com/lqwh/p/7523213.html
Copyright © 2020-2023  润新知