2012 MUTC 7 总结
题解链接:http://page.renren.com/601081183/note/865867924
hdu题号:4360~4369
今天状态不太好。中午,我带着疲惫的身躯去到机房,但是开门的人迟迟没来,对于我们的比赛开始时间也就延迟了几分钟。今天也是很久都没有队伍带榜,不过我一打开题目就看懂了两个,一个是1006,另外的是1001。
比赛刚开始的时候,我1001还没更新题意,所以没敢试这题,不过初步可以知道是最短路。然后,我观察了一下1006的输入输出,我很快就发现这个对称图形只需统计其中一部份的可操作点的个数,然后快速幂一下,答案就出来了。我第一遍打出来的程序出现了一个问题,就是点的数目居然数多了。于是我又想了一下,画一下图,很快我又发现了,这是要统计1/8的正方形,而不是1/4,。于是我就赶紧改了,测试数据通过以后就立马扔了上去,不过返回了一个TLE。然后,我就很郁闷的想了一下,不能偷懒直接用bool数组来储存点的状态,而是应该用一个点的结构体来储存,在统计前排一下序,然后挑出非重复点,最后用1/8块中的点数来减去点的个数,这样就得到可操作点的个数了。
代码最快速度只需15ms,差距实在是大啊!
1006(hdu 4365)的代码:
1 #include <cstdlib> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 typedef __int64 ll; 9 const int maxn = 5005; 10 const ll mod = 100000007; 11 12 void scan(int &k) 13 { 14 char c; 15 while ((c = getchar()) && (c > '9' || c < '0')); 16 k = c - '0'; 17 while((c = getchar()) && (c <= '9' && c >= '0')) 18 k = k * 10 + c - '0'; 19 } 20 21 struct point 22 { 23 int x; 24 int y; 25 26 bool operator<(const point & a) const 27 { 28 if (a.x != x) return x < a.x; 29 return y < a.y; 30 } 31 } p[maxn]; 32 33 int cal(int n, int m) 34 { 35 int cnt = 0; 36 int t; 37 38 t = n / 2; 39 if (n & 1) t++; 40 if (!m) return t * (t + 1) / 2; 41 sort(p + 1, p + m + 1); 42 cnt++; 43 for (int i = 2; i <= m; i++) 44 { 45 if (p[i - 1].x == p[i].x && p[i - 1].y == p[i].y) continue; 46 cnt++; 47 } 48 49 /* 50 if (n & 1){ 51 t = n / 2; 52 for (int i = 1; i <= t + 1; i++){ 53 for (int j = i; j <= t + 1; j++){ 54 if (!mp[i][j]) cnt++; 55 } 56 } 57 } 58 else{ 59 t = n / 2; 60 for (int i = 1; i <= t; i++){ 61 for (int j = i; j <= t; j++){ 62 if (!mp[i][j]) cnt++; 63 } 64 } 65 } 66 */ 67 #ifndef ONLINE_JUDGE 68 printf("t %d\n", t); 69 #endif 70 return t * (t + 1) / 2 - cnt; 71 } 72 73 void con(int n, int &x, int &y) 74 { 75 int t = n >> 1; 76 77 if (n & 1) 78 { 79 if (x > t) x = n - x + 1; 80 if (y > t + 1) y = n - y + 1; 81 } else 82 { 83 if (x > t) x = n - x + 1; 84 if (y > t) y = n - y + 1; 85 } 86 if (x > y) 87 { 88 t = x; 89 x = y; 90 y = t; 91 } 92 } 93 94 ll work(ll k, int m) 95 { 96 ll ret = 1; 97 98 while (m){ 99 if (m & 1) ret *= k, ret %= mod; 100 k *= k; 101 k %= mod; 102 m >>= 1; 103 } 104 105 return ret; 106 } 107 108 bool deal() 109 { 110 int n, m, k; 111 int x, y; 112 113 if (scanf("%d%d%d", &n, &m, &k) == EOF) return false; 114 /* 115 for (int i = 1, end = (n >> 1) + 1; i <= end; i++){ 116 for (int j = 1; j <= end; j++){ 117 mp[i][j] = false; 118 } 119 } 120 */ 121 for (int i = 1; i <= m; i++) 122 { 123 scan(x); 124 scan(y); 125 x++; 126 y++; 127 con(n, x, y); 128 #ifndef ONLINE_JUDGE 129 printf("con x %d y %d\n", x, y); 130 #endif 131 //mp[x][y] = true; 132 p[i].x = x; 133 p[i].y = y; 134 } 135 136 m = cal((ll)n, m); 137 printf("%I64d\n", work(k, m)); 138 139 return true; 140 } 141 142 int main() 143 { 144 #ifndef ONLINE_JUDGE 145 freopen("in", "r", stdin); 146 #endif 147 while (deal()); 148 149 return 0; 150 }
我出完这题以后,我的队友已经将1003的转移方程写好了,于是我就立马让位置给他,让他赶紧打上去。dp的题代码 长度通常都不大,所以他很快就打好了。可惜的是,难得让他完成一题,结果这题是要用单调队列优化的,所以结果是TLE。然后我们花了好长时间想优化的方法,可惜还是没想到。赛后,师兄告诉我们用单调队列两边各扫一次,得到两个单调队列,然后,对于递增和递减的区间分别用两种不同的队列更新。据说还可以用二分搜索来加速,思路我已经有了,代码明天再打吧!
然后我就尝试这做1001,我把输入输出都打好了,就连拆点的操作也想好了,不过当时状态真实相当不好,忘记了spfa的写法,搞到搞半天yy了个dij+heap,最后还要写烂了,最终只好放弃。回来宿舍后,打了一遍,sample轻松通过,不过就是没想到这里可以有自环,还可以有等多个自环原地转啊转的!所以在我查看数据之前都没有意识到这个问题。当然,改过来以后就ac了。
1001(hdu 4360)的代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <queue> 5 #include <algorithm> 6 #include <map> 7 #define ONLINE_JUDGE 1 8 using namespace std; 9 10 typedef __int64 ll; 11 12 const int maxv = 1500; 13 const int maxe = 15000; 14 const ll inf = 1000000000000; 15 16 map<char, int> lt; 17 struct edge{ 18 int s, t; 19 ll l; 20 bool operator < (const edge &x) const{ 21 return s < x.s; 22 } 23 }E[maxe << 1]; 24 25 ll dis[maxv << 2]; 26 int cnt[maxv << 2], me[maxe << 1]; 27 int q[maxv << 2], qh, qt; 28 bool inq[maxv << 2]; 29 30 void init(){ 31 lt['L'] = 0; 32 lt['O'] = 1; 33 lt['V'] = 2; 34 lt['E'] = 3; 35 } 36 37 void spfa(int v, int e, int s){ 38 qh = qt = 0; 39 sort(E, E + e); 40 41 int p = 0; 42 43 for (int i = 0; i < v; i++){ 44 inq[i] = false; 45 dis[i] = inf; 46 cnt[i] = 0; 47 } 48 for (int i = 0; i < e; i++){ 49 while (p <= E[i].s) me[p++] = i; 50 } 51 while (p <= v) me[p++] = e; 52 #ifndef ONLINE_JUDGE 53 for (int i = 0; i < 20; i++){ 54 printf("me %d : %d E : %d %d %I64d dis %I64d\n", i, me[i], E[i].s, E[i].t, E[i].l, dis[i]); 55 } 56 #endif 57 58 for (int i = me[s]; i < me[s + 1]; i++){ 59 int et = E[i].t; 60 61 if (dis[et] > E[i].l) dis[et] = E[i].l; 62 cnt[et] = 1; 63 if (!inq[et]){ 64 q[qt++] = et; 65 inq[et] = true; 66 } 67 } 68 while (qh < qt){ 69 int cur = q[qh++]; 70 #ifndef ONLINE_JUDGE 71 printf("pass %d\n", cur); 72 #endif 73 74 inq[cur] = false; 75 for (int i = me[cur]; i < me[cur + 1]; i++){ 76 int et = E[i].t; 77 78 if (dis[et] > dis[cur] + E[i].l){ 79 dis[et] = dis[cur] + E[i].l; 80 cnt[et] = cnt[cur] + 1; 81 if (!inq[et]){ 82 q[qt++] = et; 83 inq[et] = true; 84 } 85 } 86 else if (dis[et] == dis[cur] + E[i].l && cnt[et] < cnt[cur] + 1){ 87 cnt[et] = cnt[cur] + 1; 88 if (!inq[et]){ 89 q[qt++] = et; 90 inq[et] = true; 91 } 92 } 93 } 94 } 95 } 96 97 98 void deal(int cc){ 99 int n, m, N; 100 101 scanf("%d%d", &n, &m); 102 N = n << 2; 103 for (int i = 0; i < m; i++){ 104 int s, t, len, kd; 105 char buf[3]; 106 107 scanf("%d%d%d%s", &s, &t, &len, buf); 108 s--; t--; 109 kd = lt[buf[0]]; 110 E[i << 1].s = kd * n + s; 111 E[i << 1].t = ((kd + 1) % 4) * n + t; 112 E[i << 1].l = len; 113 E[i << 1 | 1].s = kd * n + t; 114 E[i << 1 | 1].t = ((kd + 1) % 4) * n + s; 115 E[i << 1 | 1].l = len; 116 } 117 118 m <<= 1; 119 spfa(N, m, 0); 120 121 if (dis[n - 1] < inf) printf("Case %d: Cute Sangsang, Binbin will come with a donkey after travelling %I64d meters and finding %d LOVE strings at last.\n", cc, dis[n - 1], cnt[n - 1] / 4); 122 else printf("Case %d: Binbin you disappoint Sangsang again, damn it!\n", cc); 123 } 124 125 int main(){ 126 int T; 127 128 #ifndef ONLINE_JUDGE 129 freopen("in", "r", stdin); 130 freopen("out", "w", stdout); 131 #endif 132 init(); 133 scanf("%d", &T); 134 for (int i = 1; i <= T; i++){ 135 deal(i); 136 } 137 138 return 0; 139 }
最后半个钟,我的队友才辛苦看懂1005这原本很水的模拟题。然后就手忙脚乱的打上代码,提交了上去。思路是对的,sample也是对的,不过我一开始的时候没有处理行末的空格和最后的空行,所以直到比赛结束我们都没有通过这题。赛后改了这个问题以后就立马过了.......T^T 这下玩大了,那时还以为没改会先得到PE,结果oj实在是狠,直接返回wa,搞到我们先是觉得是想法错误了,所以更改的方向也错了......
1005(hdu 4364)的代码:
1 #include <cstdio> 2 3 int mt[4][4]; 4 int op[4][4] = {2, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 3, 1, 1, 2}; 5 6 int deal(int OP, int in){ 7 switch(OP){ 8 case 1: return in; 9 case 2: { 10 in <<= 1; 11 if (in > 0xff){ 12 in ^= 0x1b; 13 } 14 return in; 15 } 16 case 3:{ 17 int tmp = in << 1; 18 in = tmp ^ in; 19 if (in > 0xff){ 20 in ^= 0x1b; 21 } 22 return in; 23 } 24 } 25 return 0; 26 } 27 28 int main(){ 29 int T; 30 #ifndef ONLINE_JUDGE 31 freopen("in", "r", stdin); 32 #endif 33 scanf("%d", &T); 34 while (T--){ 35 for (int i = 0; i < 4; i++){ 36 for (int j = 0; j < 4; j++){ 37 scanf("%X", &mt[i][j]); 38 #ifndef ONLINE_JUDGE 39 printf("%d ", mt[i][j]); 40 #endif 41 } 42 #ifndef ONLINE_JUDGE 43 puts(""); 44 #endif 45 } 46 int out; 47 48 for (int i = 0; i < 4; i++){ 49 for (int j = 0; j < 4; j++){ 50 out = 0; 51 for (int k = 0; k < 4; k++){ 52 out ^= deal(op[i][k], mt[k][j]); 53 } 54 if (j < 3) printf("%02X ", out & 0xff); 55 else printf("%02X\n", out & 0xff); 56 } 57 } 58 59 if (T) puts(""); 60 } 61 62 return 0; 63 }
吸取教训了,以后不能靠oj来判断是否格式错误,而是要根据题意来判断!
继续努力!
——written by Lyon