zoukankan      html  css  js  c++  java
  • 1108 低价购买

    难度:提高+/省选-

    题目类型:动规

    提交次数:N

    涉及知识:线性动规

    题目描述

    “低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价(2^16范围内的正整数),你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。

    这里是某支股票的价格清单:

    日期 1 2 3 4 5 6 7 8 9 10 11 12

    价格 68 69 54 64 68 64 70 67 78 62 98 87

    最优秀的投资者可以购买最多4次股票,可行方案中的一种是:

    日期 2 5 6 10

    价格 69 68 64 62

    输入输出格式

    输入格式:

    第1行: N (1 <= N <= 5000),股票发行天数

    第2行: N个数,是每天的股票价格。

    输出格式:

    输出文件仅一行包含两个数:最大购买次数和拥有最大购买次数的方案数(<=2^31)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这2种方案被认为是相同的。

    代码:

    错误:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int a[5005];
     5 int d[5005];//以a[i]结尾的最长LIS长度 
     6 int g[5005];//以a[i]结尾的最长LIS方案数
     7 int n;
     8 int main(){
     9     int i, j;
    10     int ans = 0;
    11     cin>>n; 
    12     for(i = 0; i < n; i++){
    13         scanf("%d", &a[i]);
    14         d[i] = 1;
    15         g[i] = 0;
    16     }
    17     for(i = 0; i < n; i++)
    18         for(j = 0; j < i; j++){
    19             if(a[j]>a[i])
    20                 d[i] = max(d[i], d[j]+1);
    21             ans = max(ans, d[i]);
    22         }
    23     printf("%d ", ans);
    24     for(i = 0; i < n; i++){
    25         for(j = 0; j < i; j++){
    26             if(a[j]>a[i]&&d[j]+1==d[i]) g[i]+=g[j];
    27         }
    28         for(j = 0; j < i; j++){
    29             if(a[j] == a[i] && d[i] == d[j]) g[j] = 0;
    30         }
    31         if(d[i] == 1) g[i] = 1;
    32     }
    33     int sum = 0;
    34     for(i = 0; i < n; i++)
    35         if(d[i] == ans) sum+=g[i]; 
    36     printf("%d
    ", sum);
    37     return 0;
    38 } 

    正确:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int a[5005];
     5 int d[5005];//以a[i]结尾的最长LIS长度 
     6 int g[5005];//以a[i]结尾的最长LIS方案数
     7 int n;
     8 int main(){
     9     int i, j;
    10     int ans = 1;
    11     cin>>n; 
    12 
    13     for(i = 0; i < n; i++){
    14         scanf("%d", &a[i]); 
    15         d[i] = 1; 
    16         for(j = 0; j < i; j++){         
    17             if(a[j]>a[i])
    18                 d[i] = max(d[i], d[j]+1);
    19        
    20         }
    21         ans = max(ans, d[i]);
    22         for(j = 0; j < i; j++)
    23             if(d[j]+1==d[i]&&a[j]>a[i]) g[i]+=g[j];
    24             else if(a[j] == a[i] &&d[i] == d[j]) g[j] = 0;
    25             if(d[i] == 1) g[i] = 1;
    26     }
    27        
    28     printf("%d ", ans);
    29 
    30     int sum = 0;
    31     for(i = 0; i < n; i++)
    32         if(d[i] == ans) sum+=g[i]; 
    33     printf("%d
    ", sum);
    34     return 0;
    35 } 

    备注:

    第一段代码是有问题的!!第二个测试点WA,最后一个测试点超时。。找不到问题,回头再改

    先来说一下思路,看了很多不同的解答,参考了不同的阐述,谁让我在某些问题上理解能力比较差。。。

    统计方案数加去重的处理方法:对于每一个a[i],先统计它的方案数(这时g[i]以前的都已经进行过去重工作了),所以如果a[j]>a[i],d[j]+1==d[i],就说明d[j]一步就能转移到d[i],那直接把g[i]累加到g[j]上就好了。

    关键的是查重方法,即清零那部分比较谜。如果a[j] == a[i]并且d[i] == d[j],那么可以确定,这是完全重了的,因为j在前,方案数只能小于等于i,因此将j清零。这一点也许有点难理解。可以这么想,因为这个j循环是套在i循环里的,从LIS的第一个数开始,每一轮都会进行这个去重操作。看到有一位博主是这样阐述的:“……能转移到j上的一定也能转移到i上”。

    好吧其实我自己还是没有那么清楚,待补充。每个人都可能有自己的困惑点,举举例子试一试是个好方法。


    第二个点WA是因为ans应该初始化为1,而超时问题……太坑了!!!这题卡常数啊!老师对照着正确程序给我改了将近一个小时才过,就是能塞到一个循环里都往一个循环里塞。还有就是if(A&&B)是短路,所以尽可能把不太可能的情况往前写可以缩短时间。

    我还是鄙视这道题。

  • 相关阅读:
    Eclipse安装Hadoop插件
    (转)Ubuntu14.0.4中hadoop2.4.0伪分布模式配置
    Hadoop--DataNode无法启动
    启动与关闭hadoop
    hadoop中执行命令时发生错误
    strings命令
    Deriving data from ElasticSearch Engine
    elasticsearch data importing
    reading words in your computer and changing to female voice, linux festival text2wave saving wav files
    DDNS client on a Linux machine
  • 原文地址:https://www.cnblogs.com/fangziyuan/p/5930793.html
Copyright © 2011-2022 走看看