《TZOJ2821: Dream City》

非常好的一个题,第一眼看到就觉得是贪心或者DP。

首先,一开始的思路是枚举第k天,然后把第k天最大的放入,但是保证每天放入剩下的树中对于这一天最大的,不一定是最优方案,所以不能枚举了。

正解:dp,dp[i][j]表示到第i棵树,天数为j的最大代价。

转移很简单,但是这里直接去dp,还不太对,因为有些树可能应该在后面砍,但是它前面的树太少导致中间代价有空,导致不被算入最大代价中。

所以需要按b[i]来排序。把增长的慢的先砍,并且这样是不会受到a[i]的影响的。

可以理解一下,我们是在对树dp,所以本质上砍的那些树都是按天数排列,所以增长慢的先砍肯定更优。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 1005;
const int M = 1e6+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;

struct Node{int a,b;}p[255];
int n,m,dp[255][255];//dp[i][j] - 到第i棵树第j天的最大价值
bool cmp(Node a,Node b){return a.b < b.b;}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        n = read(),m = read();
        for(rg int i = 1;i <= n;++i) p[i].a = read();
        for(rg int i = 1;i <= n;++i) p[i].b = read();
        sort(p+1,p+n+1,cmp);
        memset(dp,0,sizeof(dp));
        for(rg int i = 1;i <= n;++i)
        {
            for(rg int j = 1;j <= m;++j)
            {
                dp[i][j] = max(dp[i-1][j-1] + p[i].a + (j-1)*p[i].b,dp[i-1][j]);
            }
        }
        printf("%d\n",dp[n][m]);
    }
    system("pause");
    return 0;
}
View Code

 

posted @ 2020-10-05 09:23  levill  阅读(145)  评论(0编辑  收藏  举报