Simple Works Gallery

起源

鄰近要大學推研究所的時刻,自己做過什麼作品來說,對於推甄時相當重要,一直都沒有好好整理過自己做過什麼,有多少能拿出檯面的項目,現在發現除了 ACM 解題和曾經幫別人寫的作業以外,沒有幾項可以吸引到人的。一樣做一個 hexo tag plugin,將作品展示櫃用一個 generator.js 的方式,將展示櫃內容呈現出來,傳入的方式為 json。同樣地,你可以在這個部落格上方的 Works 看到相關作品介紹。

下載

Download on Github

使用

仍然以 github 上的 project 為優先版本。以下的內容也許不是最新版本。

html

當前採用 json 的原因是因為可以藉由較簡單的方式,以及往後可能使用 ajax 的方式運作。這樣彈性也許會比較大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script type="text/works-gallery">
{
"works" : [
{
"title": "Chat Room Application",
"cover": "http://i.imgur.com/oUO30I6.jpg",
"description": "計算機網路-一個簡單的網路聊天室<br/> Socket programming practice (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=7ExCn1ipKeg"]
},
{
"title": "Magic Circle",
"cover": "http://i.imgur.com/Fv8ebBY.jpg",
"description": "jquery-magic-circle, write funny for friends",
"download": ["https://github.com/morris821028/jquery-magic-circle"],
"demo": ["http://morris821028.github.io/jquery-magic-circle"],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Hex Image Gallery",
"cover": "http://i.imgur.com/VMf2G1v.png",
"description": "create beautiful hexagon shapes with CSS3, jquery, write funny for friends",
"download": ["https://github.com/morris821028/jquery-hex-gallery"],
"demo": ["http://morris821028.github.io/jquery-hex-gallery/"],
"video": []
}
]
}
</script>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
.wg-container
{
background: none repeat scroll 0% 0% #2d2d2d;
border-color: #ddd;
border-style: solid;
border-width: 1px 0;
color: #ccc;
line-height: 25.6px;
margin: 0 -20px;
overflow: auto;
padding: 15px 20px;
position: relative;
text-align: center;
width: 100%;
z-index: 0;
}
.wg-container hr
{
background: #333;
background-image: -moz-linear-gradient(to right, #333, #ccc, #333);
background-image: -ms-linear-gradient(to right, #333, #ccc, #333);
background-image: -o-linear-gradient(to right, #333, #ccc, #333);
background-image: -webkit-linear-gradient(to right, #333, #ccc, #333);
border: 0;
height: 5px;
}
.wg-item
{
list-style: none;
}
.wg-item .inner
{
height: 160px;
}
.wg-item li
{
display: block;
float: left;
margin: 16px;
width: 45%;
}
.wg-item li .header
{
border: 4px solid #b4b4b4;
box-shadow: 1px 1px 1px 1px #ccc;
cursor: pointer;
float: left;
height: 256px;
margin: 5px;
moz-box-shadow: 1px 1px 1px 1px #ccc;
overflow: hidden;
position: relative;
webkit-box-shadow: 1px 1px 1px 1px #ccc;
width: 100%;
}
.wg-item li .header:hover a
{
moz-transform: scale(1.2);
ms-transform: scale(1.2);
o-transform: scale(1.2);
transform: scale(1.2);
webkit-transform: scale(1.2);
}
.wg-item li .header a
{
left: 0;
moz-transition: all 300ms ease-out;
ms-transition: all 300ms ease-out;
o-transition: all 300ms ease-out;
position: absolute;
transition: all 300ms ease-out;
webkit-transition: all 300ms ease-out;
}
.wg-item li .image
{
background-size: cover;
display: block;
height: 95%;
moz-background-size: cover;
padding: .5em;
webkit-background-size: cover;
width: 100%;
}
.wg-item li h3
{
font-size: 24px;
font-weight: normal;
line-height: 22px;
margin-bottom: 10px;
margin-top: 10px;
text-align: center;
}
.wg-item li h3 a:hover
{
text-decoration: none;
}
.wg-item li ul.links
{
float: right;
}
.wg-item li .links li
{
display: block;
margin-left: 5px;
margin-right: 0 !important;
width: initial;
}
.wg-item li .links li a
{
background: #65a9d7;
border-radius: 5px;
box-shadow: 0 1px 0 #000;
color: #fff;
font-family: Georgia,Serif;
font-size: 16px;
padding: 5.5px 11px;
text-decoration: none;
text-shadow: 0 1px 0 rgba(0,0,0,0.4);
vertical-align: middle;
webkit-border-radius: 5px;
webkit-box-shadow: 0 1px 0 #000;
}
.wg-item .description
{
font-size: 16px;
margin: .2em 0;
text-align: left;
}

hexo plugin

我已經把產生方式寫在 hexo-tag-oj 裡頭,下載使用 hexo-tag-plugin

不過相關的 js 還有 css 要自己擺放,請參考上面的描述項目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{\% ojblock works \%}
{
"works" : [
{
"title": "Chat Room Application",
"cover": "http://i.imgur.com/oUO30I6.jpg",
"description": "計算機網路-一個簡單的網路聊天室<br/> Socket programming practice (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=7ExCn1ipKeg"]
},
{
"title": "Fuzzy System",
"cover": "http://i.imgur.com/C44Hbrg.png",
"description": "計算型智慧-廣義型演算法最佳化<br/>Car simulation implements PSO, GA, and fuzzy system (Java)",
"download": ["https://github.com/morris821028/hw-FuzzySystem"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=kt2mu679elU"]
},
{
"title": "UML Editor",
"cover": "http://i.imgur.com/JCCweao.png",
"description": "物件導向程式設計-UML 編輯器架構設計<br/>OO design practice & make UML Editor (Java)",
"download": ["https://github.com/morris821028/hw-UML-Editor"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=DKDFy6uFk8Y"]
},
{
"title": "MapleStory 遊戲仿作",
"cover": "http://i.imgur.com/i62nNgG.png",
"description": "由於硬碟損壞代碼沒有救回來,只剩下舊版,收錄於 chat room 製作中的一環,由於課程時間不夠,沒有做完。 (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Magic Circle",
"cover": "http://i.imgur.com/Fv8ebBY.jpg",
"description": "jquery-magic-circle, write funny for friends",
"download": ["https://github.com/morris821028/jquery-magic-circle"],
"demo": ["http://morris821028.github.io/jquery-magic-circle"],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Hex Image Gallery",
"cover": "http://i.imgur.com/VMf2G1v.png",
"description": "create beautiful hexagon shapes with CSS3, jquery, write funny for friends",
"download": ["https://github.com/morris821028/jquery-hex-gallery"],
"demo": ["http://morris821028.github.io/jquery-hex-gallery/"],
"video": []
}
]
}
{\% endojblock \%}
Read More +

Jquery Hex Image Gallery

起源

六角形的圖片廊道,一開始給定的是提案是做出一個圖片展示櫃,可是想到要放在這個 hexo 部落格,要做到類似的相簿功能其實是很麻煩的,還有必須要關聯 generator 的產生方式,才能製作出相對的 static website,那只好將項目弄成單獨一頁,而這一頁要怎麼製作其實很難捉摸。失敗的設計總是這樣子開始的。

由於圖片量太大的話,變成一開始載入速度會太慢,因此找來了 lazyload.js,但是跟展示窗口銜接上仍有一些問題,無法適時地反映操作,所以需要 call back 操作,否則圖片會載入失敗。再者是原本六角 CSS 問題,找來網路上提供的 CSS,發現更換大型圖片的時候,會造成圖片顯示不正常,因此在這一塊費時了相當長的時間來符合預期的操作。

此項目已經放在我的 Github 上面,同時你也可以在這個 blog 上方的 Picture 中看到 demo,萬萬沒想到居然有人願意 Star 標記,真的是相當令人動容啊,從來沒想過有人對於這樣的蠢製作感興趣。

下載

Download on Github

Demo

使用

仍然以 github 上的 project 為優先版本。以下的內容也許不是最新版本。

html

為了方便產生器運行,產生方式採用 json 的生成方式。相關的動畫製作引入

  • jquery.lazyload.js 圖片動態載入
  • jquery.als.link-1.6.js 幻燈片的展示窗口 (經過修改,來完成跳轉操作)

當前採用 json 的原因是因為可以藉由較簡單的方式,以及往後可能使用 ajax 的方式運作。這樣彈性也許會比較大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script src="js/jquery.hex.gallery.js" type="text/javascript"></script>
<script src="js/jquery.lazyload.js" type="text/javascript"></script>
<script src="js/jquery.als.link-1.6.js" type="text/javascript"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
...
<script type="text/hex-gallery">
{
"album" : [
{
"cover": {"title": "<h4>THEME</h4><hr /><p>Stephanie Dola</p>", "class": "hex-1"},
"photo": [
{"imgur": "http://i.imgur.com/yIoACHc.gif"},
{"imgur": "http://i.imgur.com/uINck6K.gif"},
{"imgur": "http://i.imgur.com/zOZJEex.gif"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>萌~萌~哒~</p>", "class": "hex-2"},
"photo": [
{"imgur": "http://i.imgur.com/YSmWA3g.gif"},
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>其他</p>", "class": "hex-3"},
"photo": [
{"imgur": "http://i.imgur.com/vpKzynV.gif"},
{"imgur": "http://i.imgur.com/rctEEyS.gif"}
]
}
]
}
</script>
...
</body>
</html>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
.hex-container
{
display: block;
height: 320px;
position: relative;
width: 800px;
}
.hex
{
animation: animatedBackground 10s linear infinite;
background-color: #ccc;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: cover;
float: left;
font-family: Georgia,"Microsoft YaHei","Times New Roman",serif;
font-weight: bold;
height: 86px;
margin: 25px 5px;
moz-animation: animatedBackground 10s linear infinite;
moz-background-size: cover;
ms-animation: animatedBackground 10s linear infinite;
position: relative;
text-align: center;
webkit-animation: animatedBackground 10s linear infinite;
webkit-background-size: cover;
width: 150px;
zoom: 1;
}
.hex.hex-gap
{
margin-left: 86px;
}
.hex a
{
display: block;
height: 100%;
left: 0;
position: absolute;
text-indent: -9999em;
top: 0;
width: 100%;
}
.hex .corner-1
{
moz-transform: rotate(60deg);
ms-transform: rotate(60deg);
o-transform: rotate(60deg);
transform: rotate(60deg);
webkit-transform: rotate(60deg);
}
.hex .corner-1:before
{
moz-transform: rotate(-60deg) translate(-87px,0);
moz-transform-origin: 0 0;
ms-transform: rotate(-60deg) translate(-87px,0);
ms-transform-origin: 0 0;
o-transform: rotate(-60deg) translate(-87px,0);
o-transform-origin: 0 0;
transform: rotate(-60deg) translate(-87px,0);
transform-origin: 0 0;
webkit-transform: rotate(-60deg) translate(-87px,0);
webkit-transform-origin: 0 0;
}
.hex .corner-2
{
moz-transform: rotate(-60deg);
ms-transform: rotate(-60deg);
o-transform: rotate(-60deg);
transform: rotate(-60deg);
webkit-transform: rotate(-60deg);
}
.hex .corner-2:before
{
bottom: 0;
moz-transform: rotate(60deg) translate(-44px,-12px);
ms-transform: rotate(60deg) translate(-44px,-12px);
o-transform: rotate(60deg) translate(-44px,-12px);
transform: rotate(60deg) translate(-44px,-12px);
webkit-transform: rotate(60deg) translate(-44px,-12px);
}
.hex .corner-3
{
moz-transform: rotate(0);
ms-transform: rotate(0);
o-transform: rotate(0);
transform: rotate(0);
webkit-transform: rotate(0);
}
.hex .corner-3:before
{
moz-transform: rotate(0) translate(-12px,-44px);
ms-transform: rotate(0) translate(-12px,-44px);
o-transform: rotate(0) translate(-12px,-44px);
transform: rotate(0) translate(-12px,-44px);
webkit-transform: rotate(0) translate(-12px,-44px);
}
.hex .inner
{
color: #eee;
position: absolute;
right: 0;
top: 0;
display: inline;
float: left;
width: 98.3333%;
margin: 0px 0.833333%;
}
.hex .inner a
{
color: #fff;
text-indent: 0;
}
.hex h4
{
margin: 0;
}
.hex hr
{
border: 0;
border-top: 1px solid #eee;
margin: 15px auto;
width: 60%;
}
.hex p
{
font-size: 22px;
margin: 0 auto;
width: 80%;
}
.hex.hex-1
{
background: #74cddb;
}
.hex.hex-2
{
background: #f00;
}
.hex.hex-3
{
background: #80b971;
}
.hex.hex-back
{
background: #80b971;
}
.hex.hex-back a
{
padding: 0 4px;
}
.hex .corner-1,.hex .corner-2,.hex .corner-3
{
backface-visibility: hidden;
background: inherit;
height: 100%;
left: 0;
moz-backface-visibility: hidden;
ms-backface-visibility: hidden;
o-backface-visibility: hidden;
overflow: hidden;
position: absolute;
top: 0;
webkit-backface-visibility: hidden;
width: 100%;
}
.hex .corner-1:before,.hex .corner-2:before,.hex .corner-3:before
{
backface-visibility: hidden;
background: inherit;
background-repeat: no-repeat;
content: '';
height: 173px;
left: 0;
moz-backface-visibility: hidden;
ms-backface-visibility: hidden;
o-backface-visibility: hidden;
position: absolute;
top: 0;
webkit-backface-visibility: hidden;
width: 173px;
}
.hex-caption
{
background-color: rgba(0,0,0,0.5);
color: #fff;
left: 0;
moz-transition: all 300ms ease-out;
ms-transition: all 300ms ease-out;
o-transition: all 300ms ease-out;
position: absolute;
transition: all 300ms ease-out;
webkit-transition: all 300ms ease-out;
}
.hex:hover .hex-simple-caption
{
moz-transform: translateY(-100%);
ms-transform: translateY(-100%);
o-transform: translateY(-100%);
transform: translateY(-100%);
visibility: visible;
webkit-transform: translateY(-100%);
}
.hex-simple-caption
{
bottom: -60px;
display: block;
height: 30px;
line-height: 25pt;
text-align: center;
visibility: hidden;
width: 100%;
}
.hex-background
{
left: -80px;
position: absolute;
top: -136px;
width: 900px;
z-index: -1;
}
.hex-background .hex
{
background-color: #708090;
}
.als-viewport
{
height: 390px;
margin: 0 auto;
overflow: hidden;
position: relative;
}
.als-wrapper
{
list-style: none;
position: relative;
}
.als-item
{
cursor: pointer;
display: block;
float: left;
position: relative;
text-align: center;
}
.als-prev,.als-next
{
clear: both;
cursor: pointer;
position: absolute;
}
.als-container
{
background: none repeat scroll 0% 0% #2d2d2d;
border-color: #ddd;
border-style: solid;
border-width: 1px 0;
color: #ccc;
line-height: 25.6px;
margin: 0 -20px;
overflow: auto;
padding: 15px 20px;
position: relative;
text-align: center;
width: 100%;
z-index: 0;
}
.als-container .als-item
{
display: block;
margin: 0 5px;
margin: 0 auto;
min-height: 120px;
min-width: 100px;
padding: 4px 0;
text-align: center;
vertical-align: middle;
}
.als-container .als-prev
{
font-size: 30px;
left: 30px;
}
.als-container .als-next
{
font-size: 30px;
right: 30px;
}
.als-container .als-prev,.als-container .als-next
{
top: 175px;
}
.icon-arrow-left
{
display:inline-block;
width:32px;
height:32px;
line-height:32px;
border-top:3px solid #aaa;
border-right:3px solid #aaa;
-ms-transform:rotate(225deg);
-moz-transform:rotate(225deg);
-webkit-transform:rotate(225deg);
transform:rotate(225deg);
}
.icon-arrow-right
{
display:inline-block;
width:32px;
height:32px;
line-height:32px;
border-top:3px solid #aaa;
border-right:3px solid #aaa;
-ms-transform:rotate(45deg);
-moz-transform:rotate(45deg);
-webkit-transform:rotate(45deg);
transform:rotate(45deg);
}

架構

hex page

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="hex-container">
<div class="hex-background">
<div class="hex hex-gap" style="background-image: url();">
<div class="corner-1"></div>
<div class="corner-2"></div>
<div class="corner-3"></div>
<div class="inner"></div>
</div>
<div class="hex" style="background-image: url();">
<div class="corner-1"></div>
<div class="corner-2"></div>
<div class="corner-3"></div>
<div class="inner"></div>
</div>
...
</div>
</div>

原本網路提供 hex 只有 corner-1corner-2,這樣的做法無法產生 cover 的圖示,因此這裡增加 corner-3,但仍然會看到一條一條格線在斜邊上,不過已經相當足夠。

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="als-container" id="als-container_0" data-id="als-container_0">
<div class="als-viewport" data-id="als-viewport_0" style="width: 800px; height: 328px;">
<ul class="als-wrapper" data-id="als-wrapper_0" style="width: 4800px; height: 328px;">
<li class="als-item" data-linkid="-6" id="als-item_0_0" style="left: 0px;">
insert hex page
</li>
<li class="als-item" data-linkid="-1" id="als-item_0_0" style="left: 0px;">
insert hex page
</li>
...
</ul>
</div>
</div>

根據原本的 jquery.als-1.6.js 並沒有提供跳轉的操作,也就是說不能直接 shift 到指定位置,只能倚靠往左和往右的觸發,因此特別自己增加了 data-linkid 為操作手段。

hexo blog plugin

我已經把產生方式寫在 hexo-tag-oj 裡頭,下載使用 hexo-tag-plugin

不過相關的 js 還有 css 要自己擺放,請參考上面的描述項目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{\% ojblock hex \%}
{
"album" : [
{
"cover": {"title": "<h4>THEME</h4><hr /><p>Stephanie Dola</p>", "class": "hex-1"},
"photo": [
{"imgur": "http://i.imgur.com/yIoACHc.gif"},
{"imgur": "http://i.imgur.com/4pzxseN.jpg"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>萌~萌~哒~</p>", "class": "hex-2"},
"photo": [
{"imgur": "http://i.imgur.com/YSmWA3g.gif"},
{"imgur": "http://i.imgur.com/5IHR8bQ.gif"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>其他</p>", "class": "hex-3"},
"photo": [
{"imgur": "http://i.imgur.com/vpKzynV.gif"},
{"imgur": "http://i.imgur.com/rctEEyS.gif"}
]
}
]
}
{\% endojblock \%}

#

Read More +

專注于足下,才能走得更遠

足下

仔細想想,已經要準備迎來大四生活,也差不多是要決策是否要讀研究所的時候,而我除了 UVa 外,網頁 Web 語言也稍微懂了基礎、Linux 指令也摸了幾下、hacker 技巧也在旁圍觀了不少,算是大三這一年一大進步,過往幾年都沒有這麼快速進展過。

之前張媽媽教授說的 「學得廣不如學得深」 學廣很難,但是又稱不上獨樹一幟的可用之才,取代性難易將決定薪水 (不過分紅好像也是另外一個重點)。這一年到處摸摸也大概自己擅長什麼項目,我想目前認為可以讀讀書上的內容理解,但總是沒有記在心裡,說到印象深刻的大多都是偏向數學類型,其他記不牢的,既然書本可查,為何要記。

其實如果說學得深,寫了這麼久的 ACM-ICPC 題目,是那種拿不上檯面的新手版 C/C++,而且既然有出題必然存有代碼解答,發現擅長的不是當下想到相同的解法,而是把大家給予的解法找到一個更精簡更快速的寫法 (code) 和做法 (think) 。因為我可以沒有壓力地慢慢寫,直到了現在 UVa 2400+ ,沒有準備比賽的壓力,已知無法成為相同能力之人,那就成為平凡人最強。


這個暑假看了什麼

根據距離上一次截圖的情況看來,說說中間的空白時期

日劇

《花子與安妮》

翻拍一部小說而來,描述一個翻譯家花子的故事,至於安妮的部分遲遲沒有解釋是誰,更有網友戲稱為 《花子與貴安》 ,因為花子 (從演員 吉高由里子 飾演少女到婦女時期的時候),不斷地講了一句有一句的貴安 (有問候和祝福之意,用於語末助詞),看到 “安” 一字的出現,難免會認為是問好之意,不斷地講問候人家是否安好,還真是莫名其妙。

這個翻譯家花子,出身農稼家,但是比其他兄弟姊妹愛讀書 (雖然還看不懂文字),因此受到花子父親送到東京修女學院採用 受助生 (意思差不多是公費生) 讀到成年,就讀的時候萬萬沒想到整間學校還有規定一定要講英文的日子 (傳教士不意外),沒錯,為什麼我只是想來這裡讀書,為什麼還要受到 英文災難 ,又不是千金大小姐從小接觸英文,一上課就學這麼難的,還是學字母吧!英文寫作的時候,還偷偷修女的情書交作業呢。

因為我對英文一竅不通,為什麼要遭遇這種 ... 我只是想要飽讀自己最喜歡的書才來這裡的啊!

其實看了前面還挺有感覺的,看到英文不好的人也可以這樣翻身,但是最後就只剩下英文,可謂 窮得只剩下英文 ,不禁流涕。在 bilibili 站上撥放的 《花子與安妮》每一集都會出現 舔脖君 ,看著片頭吉高穿著和服露出修長的脖子,想必這位仁兄也按耐不住,繼續看下去也算是打發打發時間,畢竟沒有 《海女》 演得這麼活潑歡樂。

你已經成功讓我受盡恥辱了

《最高離婚》

這一部在描述兩對夫妻離婚、沒有結婚的夫妻卻要離婚,說到劇情最有趣的就是 瑛太 飾演的處女座男生,各種歡樂呢!

** 「小哥,兩個人吃的是飯,一個人吃的是飼料!」 **大家一起來吃飼料吧!每天為了吃飼料而出門,為了飼料而賺錢。

劇情起伏看似不大,笑點藏得相當豐富,建議想要細細品味的人才去看, 官方吐槽 也相當不錯呢 wwwwww,推薦給學長們看,果然生活情調和品味有所差別,導致看這部日劇的感想也是天差地遠。瑛太後來跑去當宅宅迷鄰家女生的偶像真的是太有同感了。

歌詞「備受欺凌 死宅在家 遊戲中心 是我歸宿 廢材如我 心懷大志 即便受辱 早成習慣 敬請自便 电电电电电电电电 电电电电 电電波組.inc 今天依舊 慌亂掙扎 周而復始 輪迴進化 以吾個性 奪取天下 生存之地 蕩然無存 只為夢想 現在點燃 電波激情 …」

「比起聰明有知識的人,能讓別人振作起來的人 才更有價值」

「總是問別人精神好不好的人,真的很招人煩,也有人平常就無精打采的,人家明明無精打采也活得很好,你就別用所有人都要神采奕奕的標準去過問別人的生活。」

「這裡就是我的容身之所啊!」

《同窗生》

被網友戲稱 中年偶像劇 (相對少年偶像劇,倒不是大陸《鄉村愛情》那種狗血劇情),比起隔壁棚《晝顏》相當純情多了!中年戀愛劇場似乎在日本需求也越來越高,很多日劇也開始因為演員而提高平均年齡了?

說來看這一部,一部分是因為其中兩個的演員來自於日劇《First Class》(澤尻龍英華的復出之作),蠢萌情侶組,感覺萌萌哒!原來國中同學到了 40 歲的時候,還可以這麼逗趣自在地聊天,甚至談戀愛?!多麼青澀的青春綻放啊,都有各自的孩子,仍然不以此為障礙,完成國中未完成的旅程。

嗚嗚,國中就有好感的對象到底哪裡找,國中同學會在數十年後還能召集得到不少人來聚聚,仔細想想還真不科學。也許在我這一代已經是不太可能,各自忙各自的,高中同學會去過幾次,一群台清交活得如此耀眼,前途似錦的人生就等著他們。同學會總是如此地意外連連,可以看到其他人不同的突破和演進。

「像阿遼,一直成績很好的人也會有某種人性的缺陷的。」

「你不覺得摩天輪和人生很相似嗎?一點一點地移動著,往上爬著,然而迎來頂峰,攀上最高點,之後就一路向下」

一路上成績不錯、事業有成、家境不錯的遼介,即使結了婚,卻沒想到原本妻子滿腦子只為了孩子希望丈夫能夠安穩地賺錢讓孩子上更好的學習環境,一昧地被認為只是一個賺錢機器的遼介而言,無非是一個歸不得的地方,沒有自己想要活著的家庭,於是跟蠢萌的主編 (First Class 的主編) 談情說愛,因為彼此都有工作,又有不少共同好友,交往起來沒有壓力,使得彼此之間吸引力非凡。未來將要怎麼活著,真的是一大決策。而俺們的男主角卻是從大公司辭職,因為自己原本的妻子在同一家公司上班跟同事出軌而離婚,繼承父業的洗衣店小老闆。

** 「正因為開的是洗衣店,讓各種東西付諸流水才是我所擅長的!」 **

然後遇到曾經一起 私奔 的女主角,聽到就有點犯了 FFF 團的怒火怎麼可以曾經有這一段經驗,俺曾經在網路上交網路女友 (性別不談) 的經驗也是不錯,但是沒有實體還是有段落差啊!故事還在連載中,敝人覺得還可以,平淡風味小品誠心推薦。

動畫

《歡迎加入 NHK》

這一部可是宅出頭的故事,門不出戶的宅宅如何走出門工作,中間經歷過了什麼心路歷程,某方面來說還真是遇到各種貴人 (不離不棄的基友、曾經嚮往的 學姊 以及最重要的小岬指導員),「人啊,只要餓了就會想出去工作,如果不愁基本需求的話,就會以最低需求的方式活下去。」

「足不出戶轉眼已有三年,馬上就要邁向第四年了!」

「要是靠祈禱就能治好家裡蹲的話就不用這麼辛苦了。」

「現在的你是很醜陋、沒出息、又骯髒。」

「我也很想過很普普通通的人生就好了啊。」

我想,很多人也許不明白 「為何而宅,而你不宅?」 ,不只有身理上的宅,心理層面也可以宅,如果知道未來沒有目標,那為什麼要奮鬥?如果不能對社會有所貢獻,活著又是為了什麼?沒有皮膚的那一層面紗,更沒有如聖人般的個性,那到底又是要怎麼與世間接軌。女主小岬想要藉由指導男主走出 NEET 來得到對自己的救贖, 「這麼做,感覺至少還有人需要我」 小岬的這一套心聲不斷地在心裡溢滿,不擅長的事情太多,總覺得沒人需要我,就算有人需要我,但覺得自己做得不夠好,會帶給別人失望和困擾。

「沒想到 ... 會在這種地方迎接我人生的結局啊」

「可是 ... 能夠跟她(學姊)一起的話,也就無所謂了。」

「因為就算真的有神明存在,祂也一定是壞人。」

** 學姊 **「我們的人生到底有什麼意義呢?」

「祝你幸福, 學姊」

「我是個超級御宅族啦」

「去死吧,噁心的御宅混蛋,像你們這種爛人都從世上消失吧!」

故事結尾不是相當耀眼的一頁,雖不是耀眼的光輝,起碼也是有一片曙光在, 「昏暗不明的光芒比起什麼都沒有都好。」 擷取自《The Knick 尼克病院》,何等樂觀的說法!上一句的對話是 「世間上沒有變得更好的解藥」來自於莎士比亞。看這一部動畫,甚至還覺得比不上男主,沒遇過那樣的 學姊 ,更別說小岬這般救世主的存在,其實學姊是個外貌不錯,性格卻相當低沉的人,正因為外貌的讒言不在少數,祝學姊幸福,找到一個不錯的伴侶 (;´Д`)

經歷了自殺派對、網路沉迷、GAL GAME 製作、外出指導、受到老鼠會的詐欺 … 等,故事不少社會寫實,小岬果然是半翼天使,也好想跟天使簽訂契約啊。裡面不離不棄的基友跟著學長 (男主) 一起奮鬥一段時間,也教會了男主如何不被網路性別給欺騙,這麼感人的反串腳色,真的不推不行。

《妄想代理人》

這一部是今敏作品,主要好看的是第八集,其他的主題比較偏向意識流,這部動畫本身也是一部妄想,當妄想成為謠言,每個人就會將自己的不愉快找一個妄想的代理人來宣洩,這也是最主要的含意,代理人本身不存在,但是人們把妄想投到同一個不存在的實體,久而久之,大家都誤信了這個代理人的存在。

裡面最有趣的還是片頭、片尾曲,詭異的風格稱不上難聽,搭配動畫顯得相當有深意,也許偷偷被暗示了什麼呢。今敏導演已經過世了,受到癌症的折磨,不得不把其中一部作品中斷製作,今敏的遺書寫得相當有內容,有趣的人可以去查閱一下,這讓我想到 《歡迎加入 NHK》 裡頭也一段名人遺書的對談,寫了《人間失格》的太宰治到底寫了什麼樣的遺書呢?

「要和大家一起死」

「世道不濟,連死神都忙得顧不上我們了」

「那麼 ... 終於要 ...」

啊啊啊啊

喂喂,下次要怎麼死呢?

電影

《莫札特》

一部自傳類型的電影,描述音樂神童的莫札特一生以及看似基友卻心懷忌妒的朋友,莫札特雖然過得相當不懂禮數、相當荒誕的生活,但也是因為這樣的緣故,能夠創作出出格的作品,最後因為長時間沒有曬到太陽又加上過勞而死,在寫完最後一部委託歌曲而睡眠中死去。

不得不說這一部片長有點久,真羨慕他的一生可以被後人拍篇成電影,他所做的各種曲目沒有任何的草稿備份,總是一次完成所有音調,為了過著他荒誕糜爛的生活,他只好不斷地創作歌曲來換取那微薄收入,但是很不幸地能知曉他能力價值的人很少,怕得罪上頭的人而不敢接受新穎的曲風和內容,當下能不必言諱的只有莫札特,知音者少啊!只有那心懷忌妒的朋友想要收他的創作為己用能理解他的好。不得不說, 「最討厭你的人,有時反而是最理解你的人。」

就好像是生理上的慾望,卻又不給我施展的才華

給我能力,請求你

笑我,把我的平庸展現給大家看

你也差不多啊?你只會在吃東西時才離開房間

我有我的才能,而你有的是財富


這個暑假做了什麼

老妮可說的 AI 對話部分,真是覺得相當困難去完成呢。

UVa 2200-2400

兩個月衝個將近 200 題大致上沒有問題,倚靠前人們留下的足跡,我還能更強。當然原本是想要做點別的事情,畢竟有時候每天寫個 5 ~ 10 題,整天就這樣沒了,上司老妮可提議要不要繼續寫到 2400,雖然已經被喊到 3000 題,不過仔細想像除了精盡人亡外,根本突破不了數學和題目理解的障礙,時間上似乎也辦不到,總之還是到了最初曾提議的 2400。來到了 World List Rank 10 (個人認為當作是宅排行也不錯,畢竟題目不難,慢慢解還是相當容易的,恆心是難的)。

Web Design

這也是老妮可的提案,因此也做來玩玩,不少也都是套用加修改,從基礎打起不太可能。談到設計,我的演化速度還真是慢,總是創造出非常人使用的格式和操作。

六角形的圖片廊道,一開始給定的是提案是做出一個圖片展示櫃,可是想到要放在這個 hexo 部落格,要做到類似的相簿功能其實是很麻煩的,還有必須要關聯 generator 的產生方式,才能製作出相對的 static website,那只好將項目弄成單獨一頁,而這一頁要怎麼製作其實很難捉摸。失敗的設計總是這樣子開始的。

由於圖片量太大的話,變成一開始載入速度會太慢,因此找來了 lazyload.js,但是跟展示窗口銜接上仍有一些問題,無法適時地反映操作,所以需要 call back 操作,否則圖片會載入失敗。再者是原本六角 CSS 問題,找來網路上提供的 CSS,發現更換大型圖片的時候,會造成圖片顯示不正常,因此在這一塊費時了相當長的時間來符合預期的操作。

此項目已經放在我的 Github 上面,同時你也可以在這個 blog 上方的 Picture 中看到 demo,萬萬沒想到居然有人願意 Star 標記,真的是相當令人動容啊,從來沒想過有人對於這樣的蠢製作感興趣。

鄰近要大學推研究所的時刻,自己做過什麼作品來說,對於推甄時相當重要,一直都沒有好好整理過自己做過什麼,有多少能拿出檯面的項目,現在發現除了 ACM 解題和曾經幫別人寫的作業以外,沒有幾項可以吸引到人的。一樣做一個 hexo tag plugin,將作品展示櫃用一個 generator.js 的方式,將展示櫃內容呈現出來,傳入的方式為 json。同樣地,你可以在這個部落格上方的 Works 看到相關作品介紹。

中斷的虛擬機課程

這個課程的理論並不難懂,假設環境在 Ubuntu 上的 KVM,進行不中斷的 migration 操作,多個電腦共用同一個硬碟操作,將其中一台機器的記憶體內容 copy 到另外一台機器上,然後將服務傳給另一台工作,這樣的好處在於可以不長時間中斷服務。

而我們採用的 project 就是要測試這個不中斷的服務,因此需要一個 web application,寫了一個 nodejs 寫的 upload server,如果要用之前寫的 travis reporter 提供的 web socket 來完成 chat room 也是可以的,不過最麻煩的還是在於虛擬機的架設,要用橋接器 bridge 來連入實體機上的虛擬機,由於有網路層面的操作,分配 ip 的個數造成相當大的困擾,通常伴隨著子網域的操作會比較方便,這樣不中斷服務才能更為明顯,更新 router、DNS 的時間才會縮短,才不會造成 TCP 嘗試時間過長而中斷。

但是這樣的環境相當難架設,少說幾乎要 3 個 ip 和 2 台機器,沒有實驗室的我而言,生出這樣環境是相當困難的,在此之前已經將 web application 到位完成,隨後跟著同組的學長一層一層突破網卡和 VM 設定問題,但是之後一位學長研究所換學校,而另一個跟著教授指導跑去忙產學合作,於是我選擇放棄接下來的製作。


雜事小記

七月

這一個月還在上虛擬機課程,每隔一到兩天上一次課,剩餘時間都在寫 UVa、blog 設定、 妮可 project、右下角 ukagaka 的設計,娛樂就是看動畫、日劇、晚上出門跑步。過著相當單調的生活。暑宿在學校,在只有一個人申請的房間內度過,沒有任何學長或者是同學在附近,學長們大部分都畢業搬走,剩我一個人呢。

真羨慕幾位學長可以免役不當兵,於是學長就去科技公司上班,有幾次還來問一下公司代碼的製作和撰寫,其實我會的只有演算邏輯和基礎 STL Library 使用,能幫上忙的項目相當少,也許充當工程師的黃色小鴨 (找一個定物進行描述問題本身,然後說到一半自然會有解答) 吧。

八月

已經五個多月沒有回家,這時候我姊叫我去東華大學工讀個五天,工讀的內容就是教師研習活動的相關事宜,只是沒想到大部分教師都是我的高中老師啊!國文、數學、化學、生物老師們都來了,這是何等殘酷考驗,這個不成才的傢伙有什麼臉面對老師, 「我已經快撐不下去了」 不斷地在心中默念。

跟著原本東華大學的大哥大姊們一起工作,沒想到東華大學居然有所謂的五年大學碩,也許是因為科系問題,大四就可以預讀研究所課程,再讀一年就可以碩班畢業,神秘的設計,對於工作還是很笨拙,腦子太久沒做生活操作,即使是泡茶端點心都會有問題呢。

在家生活兩個星期,下學期打算住外面了,宿舍不好抽也怕室友。兩個星期後回到中央,發現暑宿宿舍居然有人來住?偷住?房間凌亂的曾度難以想像,這實在是太可怕了。目前住在學校外面,一個人也要過得萌~萌~哒!

別校同學問道今年要不要參加 NCPC ,這讓我遲疑了一會,要找小夥伴呢,真怕露出本性和傷害別人之間的感情呢。受到比賽的創傷後,為什麼還要不斷地虐待自己啊。有小夥伴 (如 inker 神) 願意包容我的話,我當然義不容辭加入,來找我吧 (つд⊂)

為什麼


感謝

  • 調教兼指導-老妮可

附錄

『no medicine in the world can do thee good』
『even a dim light is better than no light at all』

It's where I live.

就算興奮也得忍住

不行,會興奮的

Read More +

a577. 高精度乘法

Problem

這題十分直接,就是要你計算兩個很大的數字的乘積。

Sample Input

1
2
3
4
5
0
5
11
12

Sample Output

1
2
0
132

Solution

快速傅立葉 FFT 對我來說也是一知半解,但是我能知道他計算旋積可以在 O(n log n) 完成 n 個答案結果。

旋積計算就是對於維度為 n 的兩個向量,相互作內積,其中一個向量不斷地作 rotate shift right 的操作,因此會有 n 個內積結果。

如果要套用在這一題,相當於操作多項式乘法的計算,舉個例子來說

123 x 456

相當於下面兩個向量作旋積

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(3, 2, 1, 0, 0, 0, 0, 0)
(0, 0, 0, 0, 0, 4, 5, 6)
dot = 0
(3, 2, 1, 0, 0, 0, 0, 0)
(0, 0, 0, 0, 4, 5, 6, 0)
dot = 0
(3, 2, 1, 0, 0, 0, 0, 0)
(0, 0, 0, 4, 5, 6, 0, 0)
dot = 0
(3, 2, 1, 0, 0, 0, 0, 0)
(0, 0, 4, 5, 6, 0, 0, 0)
dot = 4
(3, 2, 1, 0, 0, 0, 0, 0)
(0, 4, 5, 6, 0, 0, 0, 0)
dot = 13

如此類推,不過 FFT 只能使用 double 運算,因此在儲存精度上不是很好拿捏,誤差大概在 1e-1 ~ 1e-2 之間。

感謝 liouzhou_101 的誤差指導

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <math.h>
#include <iostream>
#include <map>
#include <complex>
#include <cmath>
using namespace std;
#define for if (0); else for
using namespace std;
const int MaxFastBits = 16;
int **gFFTBitTable = 0;
int NumberOfBitsNeeded(int PowerOfTwo) {
for (int i = 0;; ++i) {
if (PowerOfTwo & (1 << i)) {
return i;
}
}
}
int ReverseBits(int index, int NumBits) {
int ret = 0;
for (int i = 0; i < NumBits; ++i, index >>= 1) {
ret = (ret << 1) | (index & 1);
}
return ret;
}
void InitFFT() {
gFFTBitTable = new int *[MaxFastBits];
for (int i = 1, length = 2; i <= MaxFastBits; ++i, length <<= 1) {
gFFTBitTable[i - 1] = new int[length];
for (int j = 0; j < length; ++j) {
gFFTBitTable[i - 1][j] = ReverseBits(j, i);
}
}
}
inline int FastReverseBits(int i, int NumBits) {
return NumBits <= MaxFastBits ? gFFTBitTable[NumBits - 1][i] : ReverseBits(i, NumBits);
}
void FFT(bool InverseTransform, vector<complex<double> >& In, vector<complex<double> >& Out) {
if (!gFFTBitTable) { InitFFT(); }
// simultaneous data copy and bit-reversal ordering into outputs
int NumSamples = In.size();
int NumBits = NumberOfBitsNeeded(NumSamples);
for (int i = 0; i < NumSamples; ++i) {
Out[FastReverseBits(i, NumBits)] = In[i];
}
// the FFT process
double angle_numerator = acos(-1.) * (InverseTransform ? -2 : 2);
for (int BlockEnd = 1, BlockSize = 2; BlockSize <= NumSamples; BlockSize <<= 1) {
double delta_angle = angle_numerator / BlockSize;
double sin1 = sin(-delta_angle);
double cos1 = cos(-delta_angle);
double sin2 = sin(-delta_angle * 2);
double cos2 = cos(-delta_angle * 2);
for (int i = 0; i < NumSamples; i += BlockSize) {
complex<double> a1(cos1, sin1), a2(cos2, sin2);
for (int j = i, n = 0; n < BlockEnd; ++j, ++n) {
complex<double> a0(2 * cos1 * a1.real() - a2.real(), 2 * cos1 * a1.imag() - a2.imag());
a2 = a1;
a1 = a0;
complex<double> a = a0 * Out[j + BlockEnd];
Out[j + BlockEnd] = Out[j] - a;
Out[j] += a;
}
}
BlockEnd = BlockSize;
}
// normalize if inverse transform
if (InverseTransform) {
for (int i = 0; i < NumSamples; ++i) {
Out[i] /= NumSamples;
}
}
}
vector<double> convolution(vector<double> a, vector<double> b) {
int n = a.size();
vector<complex<double> > s(n), d1(n), d2(n), y(n);
for (int i = 0; i < n; ++i) {
s[i] = complex<double>(a[i], 0);
}
FFT(false, s, d1);
s[0] = complex<double>(b[0], 0);
for (int i = 1; i < n; ++i) {
s[i] = complex<double>(b[n - i], 0);
}
FFT(false, s, d2);
for (int i = 0; i < n; ++i) {
y[i] = d1[i] * d2[i];
}
FFT(true, y, s);
vector<double> ret(n);
for (int i = 0; i < n; ++i) {
ret[i] = s[i].real();
}
return ret;
}
struct Polynomial {
vector<double> v;
Polynomial operator*(const Polynomial &other) const {
int n = (int) max(v.size(), other.v.size()) * 2, m;
for (m = 2; m < n; m <<= 1);
vector<double> na, nb;
na.resize(m, 0), nb.resize(m, 0);
for (int i = 0; i < v.size(); i++)
na[i] = v[i];
for (int i = 0, j = m - 1; i < other.v.size(); i++, j--)
nb[j] = other.v[i];
Polynomial ret;
ret.v = convolution(na, nb);
for (int i = 1; i < ret.v.size(); i++)
ret.v[i - 1] = ret.v[i];
ret.v[ret.v.size() - 1] = 0;
return ret;
}
};
char sa[1<<18], sb[1<<18];
long long ret[1<<19];
int main() {
while (scanf("%s %s", sa, sb) == 2) {
Polynomial a, b, c;
for (int i = (int)strlen(sa) - 1; i >= 0; i--)
a.v.push_back(sa[i] - '0');
for (int i = (int)strlen(sb) - 1; i >= 0; i--)
b.v.push_back(sb[i] - '0');
c = a * b;
memset(ret, 0, sizeof(ret));
int f = 0;
double eps = 1.5e-1;
for (int i = 0; i < c.v.size(); i++)
ret[i] = (long long) (c.v[i] + eps);
int n = (int)c.v.size();
for (int i = 0; i < n; i++) {
if (ret[i] >= 10) {
ret[i + 1] += ret[i]/10;
ret[i] %= 10;
}
}
for (int i = n; i >= 0; i--) {
if (ret[i])
f = 1;
if (f)
printf("%lld", ret[i]);
}
if (!f)
printf("0");
puts("");
}
return 0;
}
/*
0
5
11
12
*/
Read More +

b278. 说话不算话的区间求和

Problem

一个长度为n的数组a[1..n],初始值为0,。要求你维护三种操作:

1 x v :把数组的第x个元素改为v;(1≤x≤n,1≤v≤100,000,000)

2 x y :询问数组元素a[x],a[x+1],…,a[y]之和;(1≤x≤y≤n)

0 k :撤销最近的k次操作(注意,撤销操作本身也是操作,询问也算一次操作)。(1≤k≤当前操作次数)

Sample Input

1
2
3
4
5
6
2 5
1 1 1
1 2 2
2 1 2
0 2
2 1 2

Sample Output

1
2
3
1

Solution

現在學到了一種可持久化的數據精神,有一種為函數式線段樹,最簡單理解的就是採用修改不改值,而是增加新的節點,而每一次修改最多增加 O(n log n) (延著線段樹走訪路徑增加節點)

也就是說,每一次修改會根據前一次的 root 增加一個新的 root’,這是一個相當重要的一環,每一次修改會產生新的一棵線段樹,而這個新線段樹大部分節點會使用前一個線段樹的節點,因此只要針對走訪不影響的情況下,我們仍然會經過舊有的節點。

這一題最麻煩的是對於版本回溯,對於撤銷操作而言,撤銷操作可以撤銷 “撤銷操作”,因此會不斷地展開原本被撤銷的相關操作,然後又將部分操作撤銷 … 反反覆覆,後來發現只要根據當前的版本號減去要撤銷操作的總數即可返回,因此必須記錄每一次操作的線段樹結果。

套用函數式線段樹就相當簡單了!

感謝 liouzhou_101 的題意指導

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>
#include <assert.h>
using namespace std;
#define MAXBUF 8388608
struct Node {
int lson, rson;
long long sum;
} node[MAXBUF + 50];
int nodesize = 0;
int root[524288];
int build(int l, int r) {
if (l > r) return 0;
int k = nodesize++;
node[k].sum = 0;
node[k].lson = node[k].rson = 0;
if (l == r) return k;
int m = (l + r)/2;
node[k].lson = build(l, m);
node[k].rson = build(m+1, r);
return k;
}
int change(int p, int l, int r, int x, int val) {
int k = nodesize++;
node[k] = node[p];
if (l == r) {
node[k].sum = val;
return k;
}
int m = (l + r)/2;
if (x <= m)
node[k].lson = change(node[p].lson, l, m, x, val);
else
node[k].rson = change(node[p].rson, m+1, r, x, val);
node[k].sum = node[node[k].lson].sum + node[node[k].rson].sum;
return k;
}
long long query(int k, int l, int r, int x, int y) {
if (x <= l && r <= y)
return node[k].sum;
int m = (l + r)/2;
long long sum = 0;
if (x <= m) {
sum += query(node[k].lson, l, m, x, y);
}
if (y > m) {
sum += query(node[k].rson, m+1, r, x, y);
}
return sum;
}
int main() {
int n, m;
while (scanf("%d %d", &n, &m) == 2) {
root[0] = build(1, n);
int pre_ver = 0, cmd, x = 0, y = 0;
for (int i = 1; i <= m; i++) {
scanf("%d %d", &cmd, &x);
if (cmd == 0) {
y = 0;
root[i] = root[i - x - 1];
pre_ver = i;
} else if (cmd == 1) {
scanf("%d", &y);
root[i] = change(root[pre_ver], 1, n, x, y);
pre_ver = i;
} else if (cmd == 2){
scanf("%d", &y);
// printf("query root = %d\n", root[pre_ver]);
printf("%lld\n", query(root[pre_ver], 1, n, x, y));
root[i] = root[pre_ver];
pre_ver = i;
}
if (nodesize > MAXBUF) {
return 0;
}
}
}
return 0;
}
/*
2 5
1 1 1
1 2 2
2 1 2
0 2
2 1 2
*/
Read More +

a331. K-th Number

Problem

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1…n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: “What would be the k-th number in a[i…j] segment, if this segment was sorted?”
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2…5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

Sample Input

1
2
3
4
5
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output

1
2
3
5
6
3

Solution

之前使用過塊狀鏈表、歸併樹來完成這一題,其中速度快 歸併樹 > 函數式線段樹 > 塊狀鏈表,空間消耗大小 函數式線段樹 > 歸併樹 > 塊狀鏈表。

現在學到了一種可持久化的數據精神,有一種為函數式線段樹,最簡單理解的就是採用修改不改值,而是增加新的節點,而每一次修改最多增加 O(n log n) (延著線段樹走訪路徑增加節點)

也就是說,每一次修改會根據前一次的 root 增加一個新的 root’,這是一個相當重要的一環,每一次修改會產生新的一棵線段樹,而這個新線段樹大部分節點會使用前一個線段樹的節點,因此只要針對走訪不影響的情況下,我們仍然會經過舊有的節點。

為了找到區間 K 大,使用函數式線段樹有點類似於掃描線算法,對於某個時間點依序將數字放進去,然後對於區間查詢 K 大的時候,相當於對某個時間點之間作減法運算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>
#include <assert.h>
using namespace std;
struct Node {
int l, r, lson, rson;
int sum;
} node[2097152];
int nodesize = 0;
int A[131072], B[131072], root[131072];
int build(int l, int r) {
if (l > r) return 0;
int k = nodesize++;
node[k].l = l, node[k].r = r, node[k].sum = 0;
node[k].lson = node[k].rson = 0;
if (l == r) return k;
int m = (l + r)/2;
node[k].lson = build(l, m);
node[k].rson = build(m+1, r);
return k;
}
int change(int p, int x, int val) {
int k = nodesize++;
node[k] = node[p];
node[k].sum += val;
if (node[k].l == node[k].r) return k;
int m = (node[k].l + node[k].r)/2;
if (x <= m)
node[k].lson = change(node[p].lson, x, val);
else
node[k].rson = change(node[p].rson, x, val);
return k;
}
int query(int tp, int tq, int k) {
if (node[tp].l == node[tp].r)
return node[tp].l;
int t = node[node[tp].lson].sum - node[node[tq].lson].sum;
if (k <= t)
return query(node[tp].lson, node[tq].lson, k);
else
return query(node[tp].rson, node[tq].rson, k - t);
}
int main() {
int n, m, x, y, k;
while (scanf("%d %d", &n, &m) == 2) {
map<int, int> R;
for (int i = 1; i <= n; i++)
scanf("%d", &A[i]), R[A[i]] = 0;
int size = 0;
for (map<int, int>::iterator it = R.begin(); it != R.end(); it++) {
it->second = ++size;
B[it->second] = it->first;
}
nodesize = 1;
root[0] = build(1, size);
for (int i = 1; i <= n; i++) {
A[i] = R[A[i]];
root[i] = change(root[i-1], A[i], 1);
}
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &x, &y, &k);
printf("%d\n", B[query(root[y], root[x-1], k)]);
}
}
return 0;
}
/*
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
*/
Read More +

UVa 12730 - Skyrk's Bar

Problem

紳士們上小便的時候,彼此之間會隔著 K 個小便斗 (空著人的小便斗),請問當有 N 個一排的小便斗,請問壅塞個數的期望值為何 (一次平均可以多少人上小便)。

Sample Input

1
2
3
4
3
4 2
7 2
10 3

Sample Output

1
2
3
Case #1: 1.5000
Case #2: 2.2857
Case #3: 2.4133

Solution

狀態紀錄 dp[i] 表示 i 個一排的小便斗的壅塞期望值。

現在考慮最後一個進入的人所佔的位置 p,則期望值會等於 1 + dp[p-K-1] + dp[i-(p+K)],分別為左側和右側的期望值,儘管左右兩側狀態也會對邊界有空隙 <= K,但是放入之後與 p 之間空隙最 <= 2K,也塞不下其他人 (至少要 2K + 1)。

由於最後一個人的情況有 i 種,每一種的機率都相同,因此推導結果為 dp[i] = 1 + (dp[1] + dp[2] + ... + dp[i-k-1])/i

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string.h>
#include <assert.h>
using namespace std;
double dp[1048576], sum[1048576];
int main() {
int testcase, cases = 0;
int n, m;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
if (i <= m) {
dp[i] = 1;
} else {
dp[i] = 1 + sum[i - m - 1] * 2.0 / i;
}
sum[i] = sum[i - 1] + dp[i];
}
printf("Case #%d: %.4lf\n", ++cases, dp[n]);
}
return 0;
}
/*
3
4 2
7 2
10 3
*/
Read More +

UVa 12707 - Block Meh

Problem

給 N 個區間 [l, r],每一次挑選一個區間 [a0, b0],接著可以找到另外一個區間 [ai, bi][a0, b0] 完全覆蓋 (a0 < ai < bi < b0),接著再對這個區間 [ai, bi] 再找一個被完全覆蓋的區間 [ai+1, bi+1] 如此迭代下去,當作一次操作。

請問至少要幾次,才能將所有區間挑選完。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
2
4
1 5
2 5
3 5
3 4
4
1 5
2 4
3 5
3 3

Sample Output

1
2
Case 1: 3
Case 2: 2

Solution

對右端點進行遞增排序,對左端點進行次遞增排序,接著進行掃描算法,每一次放入的區間盡可能被之前的區間包含住,否則將會增加一次操作,也就是說要找盡可能接近的左端點來符合放入的區間。

這個操作方式,非常接近 O(n log n) LIS 的思路。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string.h>
#include <assert.h>
using namespace std;
bool cmp(pair<int, int> a, pair<int, int> b) {
if (a.second != b.second)
return a.second < b.second;
return a.first < b.first;
}
#define INF 0x3f3f3f3f
int main() {
int testcase, cases = 0;
int n, s, e;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d", &n);
vector< pair<int, int> > D;
for (int i = 0; i < n; i++) {
scanf("%d %d", &s, &e);
D.push_back(make_pair(s, e));
}
sort(D.begin(), D.end(), cmp);
vector<int> leftside;
for (int i = 0; i < D.size(); i++) {
int pos = (int)(lower_bound(leftside.begin(), leftside.end(), D[i].first + 1)
- leftside.begin());
if (pos == leftside.size()) {
leftside.push_back(D[i].first);
} else {
leftside[pos] = D[i].first;
}
}
printf("Case %d: %d\n", ++cases, (int)leftside.size());
}
return 0;
}
Read More +

UVa 12701 - The Twin Head Dragon

Problem

給一棵樹,每次覆蓋不重疊的路徑,將路徑上的權重平均得到此次花費,目標覆蓋所有的邊,加總花費最小化。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
4
0 2 1
1 2 2
2 3 3
6
0 1 10000
0 2 10000
0 3 1
0 4 1
0 5 10000
0

Sample Output

1
2
3.5000
15001.5000

Solution

對於每一種狀態作紀錄,然後對於尚未使用過的邊作 bitmask,每次移除一條路徑上的結果。

// 後來發現似乎可以直接轉成有根樹,進行樹形 dp,真是失策。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string.h>
#include <assert.h>
using namespace std;
struct Edge {
int to, w, i;
Edge(int a = 0, int b = 0, int c = 0):
to(a), w(b), i(c) {}
};
vector<Edge> g[16];
int n, used[1<<16];
double dp[1<<16];
double dfs(int);
void dfs2(int u, int mask, int w, int e, int o) {
if (e) {
dp[o] = min(dp[o], dfs(mask) + (double)w/e);
}
for (int i = 0; i < g[u].size(); i++) {
if ((mask>>g[u][i].i)&1) {
int v = g[u][i].to;
dfs2(v, mask^(1<<g[u][i].i), w + g[u][i].w, e+1, o);
}
}
}
double dfs(int mask) {
if (mask == 0) return 0;
if (used[mask]) return dp[mask];
used[mask] = 1;
double &ret = dp[mask];
ret = 1e+30;
for (int i = 0; i < n; i++) {
dfs2(i, mask, 0, 0, mask);
}
return ret;
}
int main() {
int x, y, w;
while (scanf("%d", &n) == 1 && n) {
for (int i = 0; i < n; i++)
g[i].clear();
for (int i = 0; i < n - 1; i++) {
scanf("%d %d %d", &x, &y, &w);
g[x].push_back(Edge(y, w, i));
g[y].push_back(Edge(x, w, i));
}
memset(used, 0, sizeof(used));
printf("%.4lf\n", dfs((1<<(n-1)) - 1));
}
return 0;
}
/*
4
0 2 1
1 2 2
2 3 3
6
0 1 10000
0 2 10000
0 3 1
0 4 1
0 5 10000
0 */
Read More +

UVa 12674 - Go up the ultras

Problem

一個山峰高度 h[i] 如果算是突起,則必須符合

  • 到其他更高的山峰之間有經過低於 h[i] - 150000 的可能
  • 如果本身就是最高峰,則高度至少要 150000

Sample Input

1
2
3
4
5
0 10000 100000 884813 0
7
0 100000 0 200000 180000 200000 0

Sample Output

1
2
4
4 6

Solution

維護一個遞增的單調堆,而第二個元素存放掃描時經過的最低點。然後從左往右掃一次、再從右往左掃一次,分別得到每一個點往左、往右找到最高峰的情況。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <vector>
#include <stack>
using namespace std;
int n;
int h[1048576], a[1048576];
int main() {
while(scanf("%d", &n) == 1) {
for (int i = 0; i < n; i++)
scanf("%d", &h[i]), a[i] = h[i];
stack< pair<int, int> > stk;
for (int i = 0; i < n; i++) {
if (!stk.empty()) {
stk.top().second = min(stk.top().second, h[i]);
}
while (!stk.empty() && stk.top().first <= h[i]) {
pair<int, int> p = stk.top();
stk.pop();
if (!stk.empty())
stk.top().second = min(stk.top().second, p.second);
}
if (!stk.empty()) {
a[i] = min(a[i], h[i] - stk.top().second);
}
stk.push(make_pair(h[i], h[i]));
}
while (!stk.empty())
stk.pop();
for (int i = n - 1; i >= 0; i--) {
if (!stk.empty()) {
stk.top().second = min(stk.top().second, h[i]);
}
while (!stk.empty() && stk.top().first <= h[i]) {
pair<int, int> p = stk.top();
stk.pop();
if (!stk.empty())
stk.top().second = min(stk.top().second, p.second);
}
if (!stk.empty()) {
a[i] = min(a[i], h[i] - stk.top().second);
}
stk.push(make_pair(h[i], h[i]));
}
int f = 0;
for (int i = 0; i < n; i++) {
if (a[i] >= 150000) {
if (f++) printf(" ");
printf("%d", i + 1);
}
}
puts("");
}
return 0;
}
/*
5
0 10000 100000 884813 0
7
0 100000 0 200000 180000 200000 0
*/
Read More +