usaco4.3.1 Buy Low, Buy Lower

一 原题

Buy Low, Buy Lower

The advice to "buy low" is half the formula to success in the stock market. But to be considered a great investor you must also follow this problems' advice:

"Buy low, buy lower"

That is, each time you buy a stock, you must purchase more at a lower price than the previous time you bought it. The more times you buy at a lower price than before, the better! Your goal is to see how many times you can continue purchasing at ever lower prices.

You will be given the daily selling prices of a stock over a period of time. You can choose to buy stock on any of the days. Each time you choose to buy, the price must be lower than the previous time you bought stock. Write a program which identifies which days you should buy stock in order to maximize the number of times you buy.

By way of example, suppose on successive days stock is selling like this:

 Day   1  2  3  4  5  6  7  8  9 10 11 12
Price 68 69 54 64 68 64 70 67 78 62 98 87

In the example above, the best investor (by this problem, anyway) can buy at most four times if they purchase at a lower price each time. One four day sequence (there might be others) of acceptable buys is:

Day    2  5  6 10
Price 69 68 64 62

PROGRAM NAME: buylow

INPUT FORMAT

Line 1:N (1 <= N <= 5000), the number of days for which stock prices are available.
Line 2..etc:A series of N positive space-separated integers (which may require more than one line of data) that tell the price for that day. The integers will fit into 32 bits quite nicely.

SAMPLE INPUT (file buylow.in)

12
68 69 54 64 68 64 70 67
78 62 98 87

OUTPUT FORMAT

Two integers on a single line:

  • the length of the longest sequence of decreasing prices
  • the number of sequences that have this length

In counting the number of solutions, two potential solutions are considered the same (and would only count as one solution) if they repeat the same string of decreasing prices, that is, if they "look the same" when the successive prices are compared. Thus, two different sequence of "buy" days could produce the same string of decreasing prices and be counted as only a single solution.

SAMPLE OUTPUT (file buylow.out)

4 2



二 分析

给一个长度不超过5000的数组,第一问求最长递减子序列的长度,第二问以及有多少个不同的最长递减子序列。第一问经典DP,dp[i]表示以第i个数结束的最长递减子序列长度。
第二问有点麻烦,如果数组中没有重复的数字,那么直接在DP的时候加上一个计数数组count就好了,count[i]记录以第i个数结尾,长度为dp[i]的子序列个数。
但是这样对于"2 1 2 1 2 1"这样的输入,会统计出来有3个长度为2的递减子序列。题目中说明了此时应当只记1个有效子序列。那么就需要去重。我去重的方法是开一个front数组,front[i]记录的是在第i个数前,与第i个数相等的最近的数字的下标。。这样每次统计出count[i]之后递归的减count[front[i]]就可以了。。
最后:这题的出现次数需要用大整数。所以用JAVA写了。。在usaco交的时候java文件名一定要是PROB名。。。


三 代码

运行结果:
USER: Qi Shen [maxkibb3]
TASK: buylow
LANG: JAVA

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.137 secs, -1194644 KB]
   Test 2: TEST OK [0.173 secs, -1194644 KB]
   Test 3: TEST OK [0.122 secs, -1194644 KB]
   Test 4: TEST OK [0.122 secs, -1194644 KB]
   Test 5: TEST OK [0.209 secs, -1194644 KB]
   Test 6: TEST OK [0.259 secs, -1194644 KB]
   Test 7: TEST OK [0.266 secs, -1194644 KB]
   Test 8: TEST OK [0.209 secs, -1194644 KB]
   Test 9: TEST OK [0.439 secs, -1194644 KB]
   Test 10: TEST OK [0.670 secs, -1194644 KB]

All tests OK.

Your program ('buylow') produced all correct answers! This is your submission #5 for this problem. Congratulations!


AC代码:
/*
ID:maxkibb3
LANG:JAVA
PROB:buylow
*/

import java.io.*;
import java.math.BigInteger;
import java.util.Scanner;

class Node {
    int len;
    BigInteger times;

    Node() {
        len = 1;
        times = new BigInteger("1");
    }
}

public class buylow {
    int n;
    int[] a = new int[5005];
    int[] front = new int[5005];
    Node[] dp = new Node[5005];

    void init() throws IOException {
        Scanner sc = new Scanner(new FileReader("buylow.in"));
        n = sc.nextInt();
        for(int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
            front[i] = -1;
            for(int j = i - 1; j >= 0; j--) {
                if(a[j] == a[i]) {
                    front[i] = j;
                    break;
                }
            }
            dp[i] = new Node();
        }
        sc.close();
    }

    void solve() throws IOException {
        for(int i = 1; i < n; i++) {
            for(int j = 0; j < i; j++) {
                if(a[j] <= a[i]) continue;
                if(dp[j].len + 1 == dp[i].len) {
                    dp[i].times = dp[i].times.add(dp[j].times);
                }
                else if(dp[j].len + 1 > dp[i].len) {
                    dp[i].len = dp[j].len + 1;
                    dp[i].times = dp[j].times;
                }
            }
            int idx = i;
            while(front[idx] != -1) {
                if(dp[i].len == dp[front[idx]].len) {
                    dp[i].times = dp[i].times.subtract(dp[front[idx]].times);
                }
                idx = front[idx];
            }
        }

        int max_len = 0;
        BigInteger max_times = new BigInteger("0");
        for(int i = 0; i < n; i++) {
            if(dp[i].len > max_len) {
                max_len = dp[i].len;
                max_times = dp[i].times;
            }
            else if(dp[i].len == max_len) {
                max_times = max_times.add(dp[i].times);
            }
        }
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("buylow.out")));
        out.println(max_len + " " + max_times);
        out.close();
    }

    void run() throws IOException{
        init();
        solve();
    }

    public static void main(String[] args) throws IOException {
        new buylow().run();
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值