贪心+模拟
第一次碰这类题,找大牛们的代码借鉴下
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int MAXN = 1005;
typedef long long ll;
struct node
{
int buy, bk, n, m;
}data[MAXN];
int w, h, a, day;
ll coin;
int num[10]; /// n格的方块最多几个
int cpNum[10], next[MAXN], sum[MAXN];
/**
贪心法,先把连续的3×3矩阵从最左上角开始铺满
对剩余的区域,先铺最右下角,再铺其他
x = w%3, y = h%3;
最右下角: 9 - (3-x)*(3-y) == 3x + 3y - xy > xy
因此: 3*3 >= x*3 || y*3 >= 3x + 3y - xy >= xy
*/
int top;
/// now-data[h].n时刻买入,计算到结束时的收益, 扩增土地
void bozhong(ll &t_mon, int id, int now)
{
int tt;
ll tmp = 0;
if (now > day) return;
if (!data[id].m)
tmp = data[id].bk;
else
tmp = (ll)data[id].bk * (ll)(1+(day-now)/data[id].m);
while (top> 0 && t_mon > 0)
{
/// 投入大于收益
if (top * tmp <= data[id].buy)
{
top = -1;break;
}
tt = min((ll)cpNum[top], t_mon/data[id].buy); /// 购买数量
t_mon -= tt * data[id].buy;
cpNum[top] -= tt;
next[now] += tt; /// 到now时刻需要播种的份数
sum[now] += tt * top; /// 到now时刻可收获的土地块数
if (cpNum[top] == 0) --top;
else break;
}
}
ll solve(int id)
{
ll res = coin;
memset(next, 0, sizeof next);
memset(sum, 0, sizeof sum);
memcpy(cpNum, num, sizeof num);
top = 9;
bozhong(res, id, data[id].n);
for (int i = 1; i<= day; ++i)
{
if (sum[i] == 0) continue;
/// 收益
res += sum[i] * data[id].bk;
/// 在原有基础上继续
if (data[id].m == 0 && i+data[id].n <= day)
{
res -= next[i] * data[id].buy;
next[i+data[id].n] += next[i];
sum[i+data[id].n] += sum[i];
}
else if (data[id].m != 0 && i+data[id].m <= day)
{
sum[i+data[id].m] += sum[i];
}
/// 扩增
bozhong(res, id, i+data[id].n);
}
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int i, j, t;
ll res;
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d%d%lld", &w, &h, &a, &day, &coin);
for (i = 0; i< a; ++i)
scanf("%d%d%d%d", &data[i].buy, &data[i].bk, &data[i].n, &data[i].m);
memset(num, 0, sizeof num);
num[9] = (w/3)*(h/3);
int x = w%3, y = h%3;
num[3*x + 3*y - x*y]++;
num[x*y] += 2;
num[3*x] += (h/3)-1;
num[3*y] += (w/3)-1;
for (i = 0, res = coin; i< a; ++i) res = max(res, solve(i));
printf("%lld\n", res);
}
return 0;
}