fzu 2281 Trades [第八届福建省大学生程序设计竞赛 Problem J Trades] [贪心]

 点击打开题目

题意: 开始有m个金币, 在接下来n天里, ACMeow可以花费ci金币去买一个物品, 也可以以ci的价格卖掉这个物品, 如果它有足够的金币, 每天可以买或卖很多次; 求它在第n天能获得的最大金币数.

分析: (1)如果序列是递增的, 设为c1, c2, c3, c4, ..., cn; 那么如果ACMeow直接在第一天买,最后一天卖, 那么它最后获得的金币数为

如果中间卖(ci)掉一次再买(cj), 最后获得的金币数为


显然ci / cj<= 1, 所以如果是递增序列, 直接在最小的时候买, 最大的时候卖即可.

(2) 如果序列是递减的, 不进行任何交易可以取得最优值

(3) 推广到一般情况, 我们将序列拆分成若干子序列, 假设序列为 1 5 8 5 2 4 6 2 , 可以拆分成1 5 8 | (8) 5 (2) | 24 6 | (6) 2, 通过观察可以发现只需在序列取得极小值的时候买, 在序列取到最大值的时候卖即可. 由于计算时数值较大且中间取模比较麻烦, 所以直接用Java的BigInteger计算比较方便.

 

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

public class Main {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		int v = 1;
		while(t-- > 0) {
			int n = cin.nextInt();
			BigInteger m = cin.nextBigInteger(), bg = new BigInteger("0");
			long cc = cin.nextLong(), c = 0;
			int f = 1;
			for(int i = 1; i < n; i++) {
				c = cin.nextLong();
				if(c > cc && f == 1) {
					bg = m.divide(new BigInteger(cc + ""));
					m = m.mod(new BigInteger(cc + ""));
					f = 0;
				}
				if(c < cc && f == 0) {
					m = m.add(bg.multiply(new BigInteger(cc + "")));
					f = 1;
				}
				cc = c;
			}
			if(f == 0) {
				m = m.add(bg.multiply(new BigInteger(c + "")));
			}
			System.out.println("Case #" + v++ + ": " + m.mod(new BigInteger("1000000007")));
		}
		cin.close();
	}
}


你可能感兴趣的:(贪心,Java)