• 洛谷 P3004 [USACO10DEC]Treasure Chest S/CSES 1097


    CSES 1097数据较弱,二位的动归数组也能过。

    Description

    一个长度为n的数列,A、B 两人轮流从数列头或尾取数。如果两人足够聪明,问A先手时可以获得的最大分数。

    Limit

    (1≤n≤5×10 ^3 ,1 leq c_i leq 5 imes 10^3)

    空间仅有64MB。

    Solution

    Solution 1 90pts

    初看这题,很容易想到区间DP!

    (f[i][j]) 表示考虑 ((i,j)) 这段区间,A能取到的最大价值。

    先暴力预处理一个前缀和数组 sum,保存每个区间的区间和,表示 A 与 B 一起取这一段区间会得到 (sum[j] - sum[i - 1]) 的分数。

    又因为A要让B拿到的分尽量小,每次只能从前面取或者后面取,那肯定要把小的给对手,大的我取走(

    不难写出转移方程:(f[i][j] = sum[i][j] - min(f[i+1][j], f[i][j-1]))

    最后答案即为 (f[1][n]),代码也很好写~

    时间复杂度:(O(n^2))

    空间复杂度:(O(n^2))

    Code 1

    // by pjx Jul.
    signed main()
    {
    	cin >> n;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> a[i];
    		f[i][i] = a[i];//初始值:长度为1的区间价值就是他本身(
    		sum[i] = sum[i - 1] + a[i];
    	}
    	for(int i = n; i >= 1; i--)
    	{
    		for(int j = i + 1; j <= n; j++)
    		{
    			f[i][j] = sum[j] - sum[i - 1] - min(f[i + 1][j], f[i][j - 1]);
    		}
    	}
    	cout << f[1][n];
    }
     
    

    但是,交上去:嗯?MLE一个点......

    Solution 2 (100pts)

    由于两维的DP数组空间过大,考虑压掉一维(

    看到每次转移时只跟 (i+1)(i-1) 有关系,考虑滚动数组,设 (f[i][j % 2]) 表示考虑 ((i,j)) 这段区间,A能取到的最大价值。

    转移方程改动一下就能过了。

    空间复杂度降至 (O(n))

    Code 2:

    // by pjx Aug.
    //滚动数组优化 
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <stack>
    #define REP(i, x, y) for(register int i = x; i < y; i++)
    #define rep(i, x, y) for(register int i = x; i <= y; i++)
    #define PER(i, x, y) for(register int i = x; i > y; i--)
    #define per(i, x, y) for(register int i = x; i >= y; i--)
    #define lc (k << 1)
    #define rc (k << 1 | 1)
    using namespace std;
    const int N = 5005;
    int n, c[N]; 
    int f[N][2], sum[N];
    int main()
    {
    	cin >> n;
    	rep(i, 1, n)
    	{
    		cin >> c[i];
    		sum[i] = sum[i - 1] + c[i];
    	}
    	for(int len = 1; len <= n; len++)
    	{
    		for(int l = 1; l + len - 1 <= n; l++)
    		{
    			int r = l + len - 1;
    			f[l][len % 2] = sum[r] - sum[l - 1] - min(f[l + 1][(len - 1) % 2], f[l][(len - 1) % 2]);
    		}
    	}
    	cout << f[1][n % 2];
    	return 0;
    }
    
  • 相关阅读:
    心跳
    UITableView 总结(一)
    scrollView的contentSize,contentInsert,contentOffset
    如何跟踪论文的作者?
    hadoop与spark执行定时任务,linux执行定时任务
    java.lang.NoSuchMethodError问题处理
    数据挖掘与机器学习的相关理解
    HBASE
    腾讯云ping不通外网
    腾讯云,激活ubuntu root登录,设置ssh
  • 原文地址:https://www.cnblogs.com/pjxpjx/p/15120797.html
Copyright © 2020-2023  润新知