bzoj2548[Cstc2002]灭鼠行动
Description
最近,有一些繁殖力很强的老鼠在下水道非常猖獗,灭鼠特工队正在计划消灭这些老鼠。下水道只有东西方向和南北方向的管道,如图所示。
灭鼠特工队的队员拥有强大的武器。他们将在某些时刻t在某些位置(x,y)放置武器。他们所使用的武器包括:
1. 强力炸弹:它的攻击范围限定在管道内部,是沿竖直和水平方向,离(x,y)的距离不超过L的区域,但是不能穿透下水道壁。它将在放置之后立刻爆炸,且攻击范围内的老鼠将被全部炸死。
2. 神秘射线:它的攻击范围是以(x,y)为圆心,半径为R的圆,而且可以穿透下水道壁。射线在时刻t施放后,将使攻击范围内的所有老鼠立刻陷入昏迷状态,失去知觉,停止一切生理活动,待到第t+3时刻才能恢复(保持失去知觉前的朝向)。如果在昏迷状态中再次受到射线攻击,那么它将再推迟3个时刻恢复。例如,若老鼠在时刻t和时刻t+1个受到一次射线的攻击,则它要昏迷到第t+3+3时刻才能恢复知觉。恢复知觉以后,老鼠将继续以前的生理活动。
3. 定时炸弹:它的攻击范围仅包括(x,y)。它在时刻t放置后,将在第t+3时刻爆炸,爆炸时处在(x,y)点的老鼠将全部被炸死。
4. 生物炸弹:它的攻击范围仅包括(x,y)。它将在放置之后立刻爆炸,使处在(x,y)点的所有老鼠的性别改变(无论大小,雌变成雄,雄变成雌),但不影响老鼠的正常生理活动。
虽然特工队的实力很强,但是老鼠的实力也不容忽视。
我们定义,相邻两个时刻之间是一个时间单位。从t=0时刻开始,每只老鼠就从初始位置向某一初始方向运动。只要前方有管道,如上图中沿方向N到达点A,老鼠就会一直向前走,运动速度为1。否则,如果只有左边或者只有右边有管道,如上图中沿方向E到达点B时,再不能沿原方向继续前进,它就会花费一个时间单位朝该方向原地转动90度,即它将改变方向朝向S。如果它左边和右边都有管道,如上图中沿方向W到达点C,老鼠会回忆这是第几次处于这种情况。如果是第奇数次遇到,它会向左转,第偶数次就向右转。如果它处于一条死路的尽头,如上图中沿方向W到达点D,那么它会花费两个时间单位连续向右转两次,即它将改变方向朝向E。
如果在t时刻某点恰好只有两只老鼠,一只为成年雄老鼠,一只为成年雌老鼠,则它们将会因为进行繁殖而在该点停留两个单位时间,t+2时刻会在该点对每个有管道的方向生出一只朝着该方向的小老鼠,南北方向为雄小老鼠,东西方向为雌小老鼠。如上图中的C点,t时刻恰好只有两只老鼠,它们都已成年且性别相异,那么在第t+2时刻就会在该点生出三只小老鼠,它们分别朝向N、S、E,性别分别是雄性、雄性、雌性。小老鼠一出生就立刻开始移动,而成年老鼠需要再休息一个时间单位,即在t+3时刻继续活动(两只老鼠都保持生育前的朝向)。小老鼠需要成长5个时间单位才会长成为成年老鼠。
特工队现在制定了一套灭鼠计划,其中包括在下水管道放置武器的位置、时间和类型。你需要帮他们计算灭鼠行动的效果,如果在该计划实施的过程中,老鼠的数量超过了某个限定值,就会爆发鼠疫。
Input
第一行为4个整数L R m n(0<=L,R<=10,1<=m,n<=50),其中L代表强力炸弹的有效攻击距离,R代表神秘射线的作用半径,m和n代表下水道平面图的规模。x坐标的范围为[1,m], y坐标的范围为[1,n]。
从第2行到第m+1行为下水道结构图。我们用方向数1代表N(北),用方向数2代表E(东),用方向数4代表S(南),用方向数8代表W(西)。第i+1行的第j个数字ci,j代表点(i,j)处有管道连接的所有方向数之和,如上图中的点B的方向数之和为12。
第m+2行为一个整数K(1<=K<=50),代表时刻0时老鼠的个数(此时老鼠都是成年的)。
第m+3行到第m+K+2行每行描述一只老鼠,包括该老鼠的初始坐标(x,y) (1<=x<=m, 1<=y<=n),朝向(’E’,’S’,’W’,’N’)以及性别(’X’=雄,’Y’=雌)。输入保证每个老鼠都在水管内。
第m+K+3行为两个整数P,Limit(1<=P, Limit<=100),分别表示特工队准备使用的武器个数以及控制鼠疫发生的老鼠数量的极限。
第m+K+4行到第m+K+P+3行每行描述一个武器,包括该武器的类型(1-强力炸弹,2-神秘射线,3-定时炸弹,4-生物炸弹),放置的时刻t(t>=1),放置的坐标(x,y) (1<=x<=m, 1<=y<=n),输入保证武器放置在管道内。武器按照放置的时间不降序排列。
最后一行包含一个整数Time(1<=Time<=1000),表示模拟的结束时刻。Time保证比所有武器的放置时刻大。
Output
包含一个整数。如果爆发了鼠疫,该整数为-1,否则该整数为时刻Time的老鼠数目。
Sample Input
6 14 12
7 15 13
3 11 9
3
1 3 W X
1 2 W X
3 3 S X
3 100
1 1 2 2
3 1 3 1
2 2 3 2
10
Sample Output
HINT
各个时刻每只老鼠的情况如下表:
时刻 |
老鼠1 |
老鼠2 |
老鼠3 |
||||||
坐标 |
朝向 |
状态 |
坐标 |
朝向 |
状态 |
坐标 |
朝向 |
状态 |
|
0 |
(1,3) |
W |
正常 |
(1,2) |
W |
正常 |
(3,3) |
S |
正常 |
1 |
N/A |
N/A |
死亡 |
(1,1) |
W |
正常 |
(3,3) |
W |
正常 |
2 |
N/A |
N/A |
死亡 |
(1,1) |
S |
正常 |
(3,2) |
W |
昏迷 |
3 |
N/A |
N/A |
死亡 |
(2,1) |
S |
正常 |
(3,2) |
W |
昏迷 |
4 |
N/A |
N/A |
死亡 |
N/A |
N/A |
死亡 |
(3,2) |
W |
昏迷 |
5 |
N/A |
N/A |
死亡 |
N/A |
N/A |
死亡 |
(3,2) |
W |
正常 |
Source
1589479
ksq2013 | 2548 | Accepted | 1368 kb | 20 ms | C++/Edit | 5120 B | 2016-08-13 19:58:14 |
我的思路:因为该题给定了模拟的结束时刻,所以可以
1.枚举时刻从0到结束时间。
0)若有机关会触发,转(1),否则转(2)。
(1)触发该时刻的灭鼠机关,模拟对老鼠产生的影响;
(2)枚举该时刻活动的老鼠,进行1);
1)枚举所有老鼠(昏迷或非昏迷)
(1)若有雌雄鼠且成长值为0(意为成年鼠)位于同一坐标,则进行繁殖,昏迷时间+3,时刻+2该点的小鼠多出三只,成长值=5。
(2)否则,若老鼠昏迷,昏迷时间--。
(3)否则,小老鼠的成长值为0则视作大老鼠。
(4)否则,小老鼠的成长值--。
hzwer的题解:
此题最大的难点在于。。。网络上下的数据第7个点数据有误,答案似乎是22
而且要非常机智的先处理炸弹,再处理繁殖,因为有可能某时刻出生的小老鼠被变性了
其余没什么坑点吧。。注意一下眩晕的老鼠不能开始繁殖,两只繁殖完的老鼠如果一次移
动后仍然在一起且这个格子没有其他老鼠就可以繁殖,而不是两只在原地不停繁殖(我的疏漏点)
反思:1.忘记考虑老鼠的行动了;
2.此处切忌,动作不可重叠(不能既繁衍又移动),时间不能重叠(不能同时解除昏迷又移动又成长),武器的优先级最高(一定在老鼠的任何行动之前发动合法的武器);
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; bool vis[111][111]; int mp[111][111],num[55][55]; int L=0,R=0,M=0,n=0,tot=0,P=0,limit=0,T=0,cur_t=0,cur_w=0; //const int dx[]={0,-1,0,1};//NESW //const int dy[]={-1,0,1,0}; int dx[4]={-1,0,1,0}; int dy[4]={0,1,0,-1}; int bin[4]={1,2,4,8}; struct mouse{ int x,y,pos,grow,breed,stu; bool sex,dead,turn; }m[111]; struct weapon{ int type,t,x,y; bool operator<(const weapon h)const{ return t<h.t; } }b[111]; inline int pw(int x) {return x*x;} inline void wp1(weapon k) { memset(vis,0,sizeof(vis)); for(int i=0;i<4;i++){ int tx=k.x,ty=k.y,l=0; vis[tx][ty]=1; while(mp[tx][ty]&bin[i]){//binary operation; tx+=dx[i],ty+=dy[i]; l++; if(l>L)break; vis[tx][ty]=1; } } for(int i=1;i<=tot;i++) if(vis[m[i].x][m[i].y]) m[i].dead=1; } inline void wp2(weapon k) { for(int i=1;i<=tot;i++) if(pw(m[i].x-k.x)+pw(m[i].y-k.y)<=R){ m[i].stu+=3; if(m[i].breed>cur_t) m[i].breed+=3; } } inline void wp3(weapon k) { for(int i=1;i<=tot;i++) if(m[i].x==k.x&&m[i].y==k.y) m[i].dead=1; } inline void wp4(weapon k) { for(int i=1;i<=tot;i++) if(m[i].x==k.x&&m[i].y==k.y) m[i].sex^=1; } inline void trigger() { weapon k=b[cur_w+1]; while(k.t==cur_t){ cur_w++; if(k.type==1)wp1(k); if(k.type==2)wp2(k); if(k.type==3)wp3(k); if(k.type==4)wp4(k); k=b[cur_w+1]; } } inline void simulation(mouse &k) { k.breed=-1; int d=k.pos,now=mp[k.x][k.y]; if(now&bin[d]){ k.x+=dx[d]; k.y+=dy[d]; return; } int l=(d+3)%4,r=(d+1)%4,b=(d+2)%4; if(now&bin[b]) now-=bin[b]; if(now==bin[l]) k.pos=l; else if(now==bin[l]+bin[r]){ k.turn^=1; if(k.turn)k.pos=l; else k.pos=r; } else k.pos=r; } inline void breed() { int tp=0; for(int i=1;i<=tot;i++) if(!m[i].dead) m[++tp]=m[i]; tot=tp; memset(num,0,sizeof(num)); for(int i=1;i<=tot;i++) num[m[i].x][m[i].y]++; for(int i=1;i<=tot;i++) if(!m[i].stu&&m[i].breed==-1&&num[m[i].x][m[i].y]==2&&!m[i].grow&&!m[i].sex) for(int j=1;j<=tot;j++) if(!m[j].stu&&m[j].x==m[i].x&&m[j].y==m[i].y&&!m[j].grow&&m[j].sex){ m[i].stu+=3; m[j].stu+=3; m[i].breed=cur_t+2;m[j].breed=cur_t+2; break; } for(int i=1;i<=tot;i++) if(m[i].breed==cur_t&&m[i].sex){ for(int k=0;k<4;k++) if(bin[k]&mp[m[i].x][m[i].y]){ tot++; m[tot].x=m[i].x;m[tot].y=m[i].y; m[tot].breed=-1; m[tot].dead=m[tot].turn=0; m[tot].stu=0; m[tot].grow=5; m[tot].pos=k; if(k==0||k==2)m[tot].sex=0; else m[tot].sex=1; } } } int main() { char ch[5]; scanf("%d%d%d%d",&L,&R,&M,&n); R=R*R; for(int i=1;i<=M;i++) for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]); scanf("%d",&tot); for(int i=1;i<=tot;i++){ scanf("%d%d",&m[i].x,&m[i].y); scanf("%s",ch); if(ch[0]=='N') m[i].pos=0; if(ch[0]=='E') m[i].pos=1; if(ch[0]=='S') m[i].pos=2; if(ch[0]=='W') m[i].pos=3; scanf("%s",ch); if(ch[0]=='Y')m[i].sex=1; else m[i].sex=0; m[i].breed=-1; } scanf("%d%d",&P,&limit); for(int i=1;i<=P;i++){ scanf("%d%d%d%d",&b[i].type,&b[i].t,&b[i].x,&b[i].y); if(b[i].type==3) b[i].t+=3; } sort(b+1,b+1+P); scanf("%d",&T); for(cur_t=0;cur_t<=T;cur_t++){ trigger();//trigger weapons; breed();//breeding; if(tot>limit) {puts("-1");return 0;} if(cur_t!=T){//T->time limit; for(int i=1;i<=tot;i++){ if(m[i].stu) m[i].stu--; else{ simulation(m[i]); if(!m[i].stu&&m[i].grow) m[i].grow--; } } } } printf("%d\n",tot); return 0; }
第一次写190行+的模拟,果然代码能力还是不足。。。