hdu - 4600 - Harvest Moon

题意:农场游戏,一块w * h的土地,有A种种子可供选择但只可以选择一种,D天的种植时间,一个人有Y的钱。每种(x种)种子,一个种下,种下的格子及周围的8个格子N[x]天后有收获(重叠的格子只算1次),每个小格子卖出去可赚P[x]元,这种种子购入时每个Q[x]元,种子有些可以多次收获,有些不可以,可以多次收获的种子在第N[x]天第一次收获后每隔M[x]天收获一次。问D天后,这人的现金最多是多少(3 ≤ w, h ≤ 100, 0 <A, D ≤ 1000, 0 < Y ≤ 100000, 0 < Q_i, P_i ≤ 1000; N_i, M_i ≤ 10000)。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4600

——>>传参时类型声明为了int,一直WA无数。。。

按天模拟(可能开始的时候,不够钱买更多的种子,以致有些空地没种子,于是有了收获有钱后并且再购买种子还有得赚则再购入种子)。

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 1000 + 10;
const int maxm = 9 + 5;

int w, h, A, D;
long long Y;
int Q[maxn], P[maxn], N[maxn], M[maxn];
int num[maxm];      //num[i]表示9个格子中占了i个有效格子的种子数
int remain[maxm];       //remain[i]表示在种植了其中的一些种子后,剩余空地中9个格子中占了i个有效格子的种子数
int harvestGrid[maxn];      //harvestGrid[i]表示i天后有收获的土地格子数
int blank[maxn];        //blank[i]表示第i天有多少空地可以种植
int p;      //一个种子,尽量种在占格子尽量多的地方
int now;        //现在是第几天

void read(){
    scanf("%d%d%d%d%I64d", &w, &h, &A, &D, &Y);
    for(int i = 1; i <= A; i++) scanf("%d%d%d%d", &Q[i], &P[i], &N[i], &M[i]);
}

void init(){
    memset(num, 0, sizeof(num));
    num[9] = (w/3) * (h/3);     //左上方
    int ww = w % 3, hh = h % 3;
    num[9-(3-ww)*(3-hh)]++;     //右下角
    num[3*hh] += w/3 - 1;       //左下方
    num[3*ww] += h/3 - 1;       //右上角
    num[ww*hh] += 2;        //左下方与右下角中间的部分和右上角与右下角之间的部分
}

bool isok(int x){       //判断这种种子是否值得购买
    if(!M[x]) return (long long)P[x] * p > Q[x] ? 1 : 0;      //时间要够,要能赚钱
    else return (long long)(1 + (D - now - N[x]) / M[x]) * p * P[x] > Q[x] ? 1 : 0;        //时间不够的话求出的是非正数,一样可以判
}

long long work(int x, long long money){
    if(D - now < N[x]) return money;        //时间不够,直接返回
    while(p >= 1){
        if(!isok(x)){       //看看是否应该买种子
            p = 0;      //没有收获的话,不用再往下扫描,因为格子越少,赚得越少,下面的一定赚不了
            break;
        }
        //最终有收获,该买
        int numOfBuy = (remain[p] < money / Q[x]) ? remain[p] : money / Q[x];        //能买到的种子的个数
        remain[p] -= numOfBuy;      //剩余空地减少
        money -= Q[x] * numOfBuy;       //用去了一部分钱
        harvestGrid[now+N[x]] += numOfBuy * p;      //更新那些可以收获的日子
        blank[now+N[x]] += numOfBuy;        //那天会新空出numOfBuy的空地,是值得种植并且能够种植的(赚的钱比原来的成本更多了)(在时间允许下)
        if(!remain[p]) p--;
        else break;     //没钱了
    }
    return money;
}

long long cal(int x){
    memset(harvestGrid, 0, sizeof(harvestGrid));        //初始时没种种子,哪一天都没有收获
    memcpy(remain, num, sizeof(num));       //初始时所有空地都没种种了,故remain == num
    memset(blank, 0, sizeof(blank));        //初始化
    p = 9;
    now = 0;
    long long money = work(x, Y);        //第一次购买完种子后剩下的钱
    for(now = 1; now <= D; now++){      //模拟D天的收获
        if(!harvestGrid[now]) continue;
        money += harvestGrid[now] * P[x];      //可以收获的话
        if(!M[x] && D - now >= N[x]){       //在时间足够的前提下,将刚刚收获的土地继续种植
            money -= Q[x] * blank[now];       //用去了一部分钱
            harvestGrid[now+N[x]] += harvestGrid[now];      //更新那些可以收获的日子
            blank[now+N[x]] += blank[now];        //那天会新空出的空地,是值得种植并且能够种植的(赚的钱比原来的成本更多了)(在时间允许下)
        }
        else if(M[x] && D - now >= M[x]){        //在时间足够的前提下,将刚刚收获的土地继续收获
            harvestGrid[now+M[x]] += harvestGrid[now];      //更新那些可以收获的日子
        }
        money = work(x, money);
    }
    return money;
}

void solve(){
    long long Max = -1;
    for(int i = 1; i <= A; i++) Max = max(Max, cal(i));
    printf("%I64d\n", Max);
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        read();
        init();
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值