【模拟】bzoj1686: [Usaco2005 Open]Waves 波纹
打完模拟题来庆祝一波:);感觉最近陷入一种“口胡五分钟打题两小时”的巨坑之中……
Description
Input
第1行:四个用空格隔开的整数Pj Bi,B2,R. P(1≤P≤5)表示石子的个数,Bi(-5×100000≤Bi≤5×100000)和B2(-5×100000≤B2≤5×100000)表示两个河堤的z坐标,R(1≤R≤5×100000)表示你要描述湖面多少秒.没有两个石子会在同一时间砸到同一地点,两个河堤一定有不同的坐标,没有石子会砸到河堤上去.
第2到P+1行:每行有三个用空格隔开的整数描述了一颗石子,X,K T(-5×100000≤X,K T≤5×100000).X.y表示石子砸的地点的坐标,T表示石子是什么时候砸下去的.
Output
输出是一个9半9的矩阵,中心在(0,0)点.左下点的坐标为(-4,-4),右上点的坐标为(4,4).这个矩阵表现的是R秒时湖面状态.
题目分析
有用的信息只有9x9的这一部分,所以我们来对于每一颗石子分别处理。
如果只是手算前两三个石头,看上去好像状态是指数阶的感觉很吓人,但实际上显然状态是与$n$同阶的(为什么我第一眼没看出来呢……)。
可以发现每一个水波到中心的曼哈顿距离相同,那么枚举水波就变得很容易了,我们来考虑如何计算反射。
注意到反射时$y$坐标是不会改变的,那只需要考虑起点和终点的$x$坐标。
有如下三种情况:
1.大坝包含了两点,所以传递没有受到任何影响。
2.大坝包住了起点,那么比较麻烦,需要考虑多次反射。
3.大坝包住了终点,那么只用考虑一次反射。
应该是有更优的写法的,不过分类讨论更稳(?)一些吧。
之后嘛,注意不要打挂就好了。
1 #include<bits/stdc++.h> 2 3 struct node 4 { 5 int a[103][103]; 6 int *const operator[](int x) 7 { 8 return a[x+50]; 9 } 10 node() {} 11 }f; 12 int stones,lRes,rRes,times; 13 int s; 14 15 int read() 16 { 17 char ch = getchar(); 18 int num = 0; 19 bool fl = 0; 20 for (; !isdigit(ch); ch = getchar()) 21 if (ch=='-') fl = 1; 22 for (; isdigit(ch); ch = getchar()) 23 num = (num<<1)+(num<<3)+ch-48; 24 if (fl) num = -num; 25 return num; 26 } 27 inline bool limit(int x, int y){return x>=-4&&x<=4&&y>=-4&&y<=4;} 28 inline bool illegal(int x) 29 { 30 if (x<-4) return (x<lRes&&lRes<=-4)||(x<rRes&&rRes<=-4); 31 if (x>4) return (x>lRes&&lRes>=4)||(x>rRes&&rRes>=4); 32 return 0; 33 } 34 void add(int x, int y, int c) 35 { 36 register int bar,cnt; 37 if (y < -4||y > 4) return; 38 if (s < x){ 39 if ((s<=lRes&&lRes<=x)||(s<=rRes&&rRes<=x)){ 40 if (s <= lRes){ 41 bar = lRes, x = 2*bar-x-1; 42 }else{ 43 cnt = 1; 44 while (x <= lRes||x >= rRes) 45 { 46 if (cnt) bar = rRes; 47 else bar = lRes; 48 x = 2*bar-x, cnt = 1-cnt; 49 if (cnt) x++; 50 else x--; 51 } 52 } 53 } 54 } 55 if (s > x){ 56 if ((x<=lRes&&lRes<=s)||(x<=rRes&&rRes<=s)){ 57 if (s >= rRes){ 58 bar = rRes, x = 2*bar-x+1; 59 }else{ 60 cnt = 1; 61 while (x <= lRes||x >= rRes) 62 { 63 if (cnt) bar = lRes; 64 else bar = rRes; 65 x = 2*bar-x, cnt = 1-cnt; 66 if (cnt) x--; 67 else x++; 68 } 69 } 70 } 71 } 72 if (limit(x, y)) f[x][y] += c; 73 } 74 void deal(int x, int y, int t) 75 { 76 if (t==0){ 77 if (limit(x, y)) f[x][y]++; 78 return; 79 } 80 s = x; 81 for (int delta=0; delta<=t; delta++) 82 { 83 add(x+delta, y+t-delta, 1), add(x+delta, y-t+delta, 1); 84 add(x-delta, y+t-delta, 1), add(x-delta, y-t+delta, 1); 85 } 86 add(x, y+t, -1), add(x, y-t, -1); 87 add(x+t, y, -1), add(x-t, y, -1); 88 t -= 2; 89 if (t==0){ 90 if (limit(x, y)) f[x][y]--; 91 return; 92 }else if (t < 0) return; 93 for (int delta=0; delta<=t; delta++) 94 { 95 add(x+delta, y+t-delta, -1), add(x+delta, y-t+delta, -1); 96 add(x-delta, y+t-delta, -1), add(x-delta, y-t+delta, -1); 97 } 98 add(x, y+t, 1), add(x, y-t, 1); 99 add(x+t, y, 1), add(x-t, y, 1); 100 } 101 int main() 102 { 103 stones = read(), lRes = read(), rRes = read(), times = read(); 104 if (lRes > rRes) std::swap(lRes, rRes); 105 for (int i=1; i<=stones; i++) 106 { 107 int x = read(), y = read(), t = read(); 108 if (t > times||illegal(x)) continue; 109 deal(x, y, times-t); 110 } 111 for (int j=4; j>=-4; j--) 112 { 113 for (int i=-4; i<=4; i++) 114 { 115 if (i==lRes||i==rRes) putchar('X'); 116 else if (f[i][j] < 0) putchar('o'); 117 else if (f[i][j] > 0) putchar('*'); 118 else putchar('-'); 119 } 120 putchar('\n'); 121 } 122 return 0; 123 }
后记
逛了一圈发现我的代码又长又慢???
END