# bzoj1033: [ZJOI2008]杀蚂蚁antbuster

www.lydsy.com/JudgeOnline/problem.php?id=1033

#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 10
#define MAXM 10
#define EPS (1e-8)

struct Point
{
int x, y;
Point(int _x = 0, int _y = 0)
: x(_x), y(_y) {}
bool operator== (const Point &a)const
{
return x == a.x && y == a.y;
}
bool operator!= (const Point &a)const
{
return x != a.x || y != a.y;
}
};
double dis(const Point &a, const Point &b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct Ant
{
Point pos, last;
long age, k, blood, life, active;
bool cake;
Ant(Point _pos, Point _last, long _age, long _k, long _blood, long _life, long _active, bool _cake)
: pos(_pos), last(_last), age(_age), k(_k), blood(_blood), life(_life), active(_active), cake(_cake) {}
bool operator< (const Ant &x)const
{
return age > x.age;
}
};

int n, m, d, r;
long T;
vector<Point> turret;
vector<Ant> ant;
long antct;
long info[MAXN][MAXN];
int hasant[MAXN][MAXN];
bool hasturret[MAXN][MAXN];
bool hascake;

void Init()
{
hascake = true;
antct = 0;
memset(info, 0, sizeof(info));
memset(hasant, 0, sizeof(hasant));
memset(hasturret, 0, sizeof(hasturret));
scanf("%d%d", &n, &m);
int s;
scanf("%d%d%d", &s, &d, &r);
while (s--)
{
int x, y;
scanf("%d%d", &x, &y);
turret.push_back(Point(x, y));
hasturret[x][y] = true;
}
scanf("%ld", &T);
}
void NewAnt()
{
if (ant.size() < 6 && !hasant[0][0])
{
long k = antct++ / 6 + 1;
long blood = 4 * pow(1.1, k);
ant.push_back(Ant(Point(0, 0), Point(0, 0), 0, k, blood, blood, 0, false));
++hasant[0][0];
}
}
void CreatInfo()
{
for (vector<Ant>::iterator i = ant.begin(); i != ant.end(); ++i)
info[i->pos.x][i->pos.y] += (i->cake ? 5 : 2);
}
bool check(int x, int y)
{
return x >= 0 && y >= 0 && x <= n && y <= m && !hasant[x][y] && !hasturret[x][y];
}
int g[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
void MoveOne(vector<Ant>::iterator x)
{
++x->active;
vector<int> cango;
for (int i = 0; i < 4; ++i)
if (check(x->pos.x + g[i][0], x->pos.y + g[i][1]) && Point(x->pos.x + g[i][0], x->pos.y + g[i][1]) != x->last)
cango.push_back(i);
if (cango.size() == 0)
{
x->last = x->pos;
return;
}
long maxinfo = 0;
for (vector<int>::iterator i = cango.begin(); i != cango.end(); ++i)
maxinfo = max(maxinfo, info[x->pos.x + g[*i][0]][x->pos.y + g[*i][1]]);
for (vector<int>::iterator i = cango.begin(); i != cango.end();)
if (maxinfo == info[x->pos.x + g[*i][0]][x->pos.y + g[*i][1]])
++i;
else
i = cango.erase(i);
Point t;
if (x->active % 5)
t = Point(x->pos.x + g[cango[0]][0], x->pos.y + g[cango[0]][1]);
else
for (int i = 1; i <= 4; ++i)
if (check(x->pos.x + g[(cango[0] - i + 4) % 4][0], x->pos.y + g[(cango[0] - i + 4) % 4][1])
&& x->last != Point(x->pos.x + g[(cango[0] - i + 4) % 4][0], x->pos.y + g[(cango[0] - i + 4) % 4][1]))
{
t = Point(x->pos.x + g[(cango[0] - i + 4) % 4][0], x->pos.y + g[(cango[0] - i + 4) % 4][1]);
break;
}
x->last = x->pos;
x->pos = t;
}
void AntMove()
{
for (vector<Ant>::iterator i = ant.begin(); i != ant.end(); ++i)
{
--hasant[i->pos.x][i->pos.y];
MoveOne(i);
++hasant[i->pos.x][i->pos.y];
if (i->pos.x == n && i->pos.y == m && hascake)
{
i->blood += i->life / 2;
if (i->blood > i->life)
i->blood = i->life;
hascake = false;
i->cake = true;
}
}
}
typedef Point Vector;
Vector operator- (const Point &a, const Point &b)
{
return Vector(a.x - b.x, a.y - b.y);
}
struct Line
{
Point p;
Vector v;
Line(const Point &a, const Point &b)
: p(a), v(b - a) {}
};
int dcmp(double a)
{
if (fabs(a) <= EPS)
return 0;
return a > 0 ? 1 : -1;
}
int GetCut(const Line &L, const Point &C, double &t1, double &t2)
{
double a = L.v.x, b = L.p.x - C.x, c = L.v.y, d = L.p.y - C.y;
double e = a * a + c * c, f = 2 * (a * b + c * d), g = b * b + d * d - 0.25;
double delta = f * f - 4 * e * g;
if (dcmp(delta) < 0)
return 0;
if (dcmp(delta) == 0)
{
t1 = t2 = -f / (2 * e);
return 1;
}
t1 = (-f - sqrt(delta)) / (2 * e);
t2 = (-f + sqrt(delta)) / (2 * e);
return 2;
}
bool CanAttack(const Point &a, const Point &b, const Point &c)
{
double t1, t2;
int k = GetCut(Line(a, b), c, t1, t2);
if (k == 0)
return false;
if (k == 1)
return dcmp(t1) >= 0 && dcmp(t1 - 1) <= 0;
else
return (dcmp(t1) >= 0 && dcmp(t1 - 1) <= 0) || (dcmp(t2) >= 0 && dcmp(t2 - 1) <= 0);
}
void TurretAct()
{
for (vector<Point>::iterator i = turret.begin(); i != turret.end(); ++i)
{
Point p(-1, -1);
double dp;
for (vector<Ant>::iterator j = ant.begin(); j != ant.end(); ++j)
{
double d = dis(*i, j->pos);
if (d <= r)
if (p.x == -1 || j->cake || dcmp(d - dp) < 0)
{
p = j->pos;
dp = d;
if (j->cake)
break;
}
}
if (p.x != -1)
for (vector<Ant>::iterator j = ant.begin(); j != ant.end();++j)
if (CanAttack(*i, p, j->pos))
j->blood -= d;
}
for (vector<Ant>::iterator i = ant.begin(); i != ant.end();)
if (i->blood < 0)
{
--hasant[i->pos.x][i->pos.y];
if (i->cake)
hascake = true;
i = ant.erase(i);
}
else
++i;
}
bool AntWin()
{
if (hascake)
return false;
for (vector<Ant>::iterator i = ant.begin(); i != ant.end(); ++i)
if (i->cake && i->pos.x == 0 && i->pos.y == 0)
return true;
return false;
}
void ShowAnt()
{
printf("%d\n", ant.size());
sort(ant.begin(), ant.end());
for (vector<Ant>::iterator i = ant.begin(); i != ant.end(); ++i)
printf("%ld %ld %ld %d %d\n", i->age, i->k, i->blood, i->pos.x, i->pos.y);
}
void DecreaseInfo()
{
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= m; ++j)
if (info[i][j])
--info[i][j];
}
void AntGrow()
{
for (vector<Ant>::iterator i = ant.begin(); i != ant.end(); ++i)
++i->age;
}
int main()
{
Init();
for (long i = 1; i <= T; ++i)
{
NewAnt();
CreatInfo();
AntMove();
TurretAct();
if (AntWin())
{
printf("Game over after %ld seconds\n", i);
ShowAnt();
return 0;
}
DecreaseInfo();
AntGrow();
}
printf("The game is going on\n");
ShowAnt();
return 0;
}