题意:农场游戏,一块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 == nummemset(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;
}