Good morning 2014

早上起来,看到手机日历已经变成了1月1日。

这是2014的早上。

新的春天

Good Morning 2014

为毛Javascript的replace支持回调函数啊,以及关于ajax返回值和feelyblog更新了

好吧。。这么长的标题我都不知道会怎么显示。

为毛Javascript的replace支持回调函数啊!!!!

害得我多费了好多时间。。。。


好吧,正文开始。

一切要从我今天突然脑洞大开想把bilibili的播放器引用到自己博客来说起。

以下是最后完成的引用代码:在文章中任何一个地方出现这个代码都可以。不过因为bilibili播放器比较长。所以还是放到一个新段落里比较好。

1
[video][[bilibiliav896743p1]][/video]

以下为av896743【玄觞、王朝——空待】

av896743p1

(↑↑2014年2月2日更新——原来演示视频被up主自己删除了。。于是我只能换一个↑↑)


网页上这部分,我用正则表达式去匹配。找到[video][/video]标签括起来的部分,然后找出里面的av号和分p号。替换成播放器。完成。嗯,就是这样一个过程。

然后播放器是只接受cid的,不是分p号。于是我去注册了一个api。。。。。为了方便的获取cid。为了节省HTML模板的代码,我在php这里就渲染成最后的HTML代码。显示模板那边只要引用就可以了。

嗯,这个api如下:

http://www.namido.net/search/biliapi/avid/[av号]/page/[分p号]

比如av894517的p1就可以直接去请求http://www.namido.net/search/biliapi/avid/894517/page/1

然后我在怎么把请求结果显示回页面上时遇到了问题。请求这东西是要用ajax的啊。。。。。。。

然后突然发现。。replace居然可以用回调函数。。。。

于是我非常简单的把最后的代码写成了这个样纸:

1
2
3
contentHtml=contentHtml.replace(/([video][[bilibiliav)(.+?)(*)(.+?)(]][/video])/g,function($0,$1,$2,$3,$4,$5){ 
return ($.ajax({url:"http://www.namido.net/search/biliapi/avid/"+$2+"/page/"+$4,async:false})).responseText;
});

就在写这一段代码的时候,我才发现,原来ajax异步读取是不能返回的。

嗯,知道了这个结论就容易想通原因了,不知道什么时候读取完嘛。所以才要回调函数这种东西。

于是就像我上面写的那样。最后换了$.ajax方法。把异步关掉,这才有了返回值这种东西。


以上这些已经更新到了新的Feelyblog r22中。

(5月2日更新——现在这些也已经在这个Wordpress博客中了,不过我比较懒,都是靠主题实现的,而没有单独做成插件)


2015年10月21日更新

新程序这些还没适配。。。

RubyWarrior——用Ruby战斗的游戏。

Ruby入门神器之——用Ruby战斗的Ruby warrior

你通过ruby控制着一个人战斗,探索,解救同伴。。。。。。


ruby

点击进入游戏

前几关都很简单。

第4关卡到我一下。最后发现,传给@healthwarrior.health居然是字符串。。。。。

我用上了@health.to_i才正常。不然用大于号就一直报错。

第6关太费劲了。。。。用了很久才解决。

思路就是,受伤了默默退回墙角回血。。

以下为代码:

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
#第6关 
class Player
@health
@wall
def play_turn(warrior)
if @wall == 1
if @health.to_i > warrior.health
if warrior.feel.enemy?
warrior.attack!
else
warrior.walk!
end
else
if warrior.health < 20
#向后退到墙边加血
if (warrior.feel:backward).wall?
warrior.rest!
else
warrior.walk!:backward
@wall=0
end
elsif warrior.feel.enemy?
warrior.attack!
else
warrior.walk!
end
end
else
if (warrior.feel:backward).captive?
warrior.rescue!:backward
elsif (warrior.feel:backward).wall?
@wall=1
else
warrior.walk!:backward
end
end
@health = warrior.health
end
end

第7关代码:

需要注意的是转身之后如果没碰到墙就继续向前走。所以要设置标志变量。

第一次我的人就不停的转身,直到超时。

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
#第7关 
class Player
@health
def play_turn(warrior)
if warrior.feel.wall?
if warrior.health < 20
warrior.rest!
else
warrior.pivot!
end
else
if warrior.feel.enemy?
warrior.attack!
elsif @health.to_i > warrior.health
if warrior.feel.enemy?
warrior.attack!
else
warrior.walk!
end
else
if warrior.health < 20
if @pivot == 1
warrior.walk!
else
warrior.pivot!
@pivot = 1
end
else
warrior.walk!
end
end
end
@health = warrior.health
end
end

第8关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#第8关 
class Player
def play_turn(warrior)
@status = warrior.look
if @status[0].captive?
warrior.rescue!
elsif (@status[1].captive?)(@status[2].captive?)
warrior.walk!
elsif @status[0].enemy?@status[1].enemy?@status[2].enemy?
warrior.shoot!
else
warrior.walk!
end
end
end

差点超时的第9关:

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
#第9关 
class Player
def play_turn(warrior)
if @step == 3
warrior.walk!
elsif @step == 2
@status=warrior.look
if @status[2].enemy?
warrior.shoot!
elsif warrior.feel.captive?
warrior.rescue!
elsif warrior.feel.wall?
warrior.pivot!
@step=3
else
warrior.walk!
end
elsif @step == 1
if warrior.feel.stairs?
if warrior.health < 20
warrior.rest!
else
warrior.pivot!
@step = 2
end
elsif warrior.feel.captive?
warrior.rescue!
elsif warrior.feel.enemy?
warrior.attack!
else
warrior.walk!
end
else
warrior.pivot!
@step = 1
end
end
end

嗯。这样9关beginner就结束了。

似乎还有进阶级别。需要从Github上download下来玩。。。

不过我就不折磨自己了。

通过这个东西真的好像会了如何写Ruby一样。。。

Codeforces 376A Lever——字符串处理

这是我最喜欢的字符串处理。。

话说这是我第一次参加Codeforces。。。这比赛最好的地方就是几乎不限制你使用的语言。。。于是我几乎是全程用PHP在写。。

最后做出来了1题。。。。嗯。。就是这道了。。。

题目太长我就不转了。具体内容请点击此链接 376A. Lever


基本上题目也没什么好说的,按照正常思路从中间的^分开。前边的倒序。然后从1开始循环和每个数字相乘。因为杠杆本身是轻的所以碰到等号直接加0跳下一个就好。

以下是AC的PHP代码:

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
<?php 
$str=fgets(STDIN);
$de=explode("^",$str);
$s1=strrev($de[0]);
$s2=$de[1];
$left=0;
$right=0;
for($i=0;$i<strlen($s1);$i++){
$te=$s1[$i];
if($te!="="){
$left+=($i+1)*intval($te,10);
}
}

for($i=0;$i<strlen($s2);$i++){
$te=$s2[$i];
if($te!="="){
$right+=($i+1)*intval($te,10);
}
}

if($left==$right) echo "balance";
else if($left>$right) echo "left";
else echo "right";
?>

HDU 2617 Happy 2009——字符串,计数器什么的

计数器就可以了系列。。。。前几天也做过一道括号匹配的题目,我好像还没发上来,也是这种思路。

按照正常思路,把所有的字符串读入,然后从前面开始减去“happy”,每去掉一个计数器加1。

——结果:华丽丽的超时了。

Problem Description

No matter you know me or not. Bless you happy in 2009.

Input

The input contains multiple test cases.

Each test case included one string. There are made up of ‘a’-‘z’ or blank. The length of string will not large than 10000.

Output

For each test case tell me how many times “happy” can be constructed by using the string. Forbid to change the position of the characters in the string. The answer will small than 1000.

Sample Input

1
2
3
4
5
hopppayppy happy

happ acm y

hahappyppy

Sample Output

1
2
3
4
5
2

1

2

Author

yifenfei

Source

奋斗的年代


然后发现,其实只要简单的在读到一个h之后给计数器1加1,读到一个a,如果前面已经有一个h了,那么计数器2加1。

坑爹的是happy里有两个p啊。。。。。。。。

然后我就发现了其实没有关系,除以二就行了嘛。

于是就有了以下的版本(注释的部分)——然后,再次华丽丽的超时。

在解决了疑似的初始化问题后。。。。。。再次华丽丽的超时。。。。。。

最后发现,我把strlen(s)提到for循环外面之后,顿时就好了。。。。。。。

にまあぁHDU你们不能开个优化啊。。。。

代码是Accepted的。其中被注释包裹着的代码是坑到我的部分——

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
//HDU happy 2009 
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main(int agrc,char *agrv[]){
char s[10086];
int f[4];
while(gets(s)){
//又被初始化坑到了。
/******初始化开始******/
for(int i=0;i<4;i++) f[i]=0;
/******初始化结束******/
int len=strlen(s);


/***********让我超时两次的大坑********/
//for(int i=0;i<strlen(s);i++){
/*******************************************/


for(int i=0;i<len;i++){
switch(s[i]){
case 'h':
f[0]++;break;
case 'a':
f[1]+=f[0]>f[1]?1:0;break;
case 'p':
f[2]+=f[1]>(f[2]/2)?1:0;break;
case 'y':
f[3]+=(f[2]/2)>f[3]?1:0;break;
}
}
cout<<f[3]<<endl;
}
}

HDU 糖果大战——概率论、坑题

Problem Description

生日Party结束的那天晚上,剩下了一些糖果,Gandon想把所有的都统统拿走,Speakless于是说:“可以是可以,不过我们来玩24点,你不是已经拿到了一些糖果了吗?这样,如果谁赢一局,就拿走对方一颗糖,直到拿完对方所有的糖为止。”如果谁能算出来而对方算不出来,谁就赢,但是如果双方都能算出或者都不能,就算平局,不会有任何糖果的得失。

Speakless是个喜欢提前想问题的人,既然他发起了这场糖果大战,就自然很想赢啦(不然可就要精光了-_-)。现在他需要你的帮忙,给你他每局赢的概率和Gardon每局赢的概率,请你给出他可能获得这场大战胜利的概率。

Input

每行有四个数,Speakless手上的糖果数N、Gardon手上的糖果数M(0<=N,M<=50)、一局Speakless能解答出来的概率p、一个问题Gardon能解答出来的概率q(0<=p,q<=1)

Output

每行一个数,表示Speakless能赢的概率(用百分比计算,保留到小数点后2位)。

Sample Input

1
2
3
4
5
50 50 0.5 0.5

10 10 0.51 0.5

50 50 0.51 0.5

Sample Output

1
2
3
4
5
0.50

0.60

0.88

Author

Speakless

Source

Gardon-DYGG Contest 2


十分典型的坑题,测试点里面有特别多的数据是坑你的。。。。害得我3次WA。

容易看出赢一次的概率为p(1-q)记为win,输一次的概率为q(1-p)记为lose,那么平一次的概率就是1-win-lose,记为tie。

f(x)为有x个糖果时候的胜率,容易看出f(x)=win*f(x+1)+lose*f(x-1)+tie*f(x)

接着,我居然尝试了递归——失败了。。。。。(←其实我觉得再改改也许能成功。)

这是个双向递推式,所以我们需要在上限和下限处各找到一个初值。根据题意f(0)=0,f(n+m)=1。(这个十分容易理解,你手上没有糖果的时候就必失败,手上存在全部糖果的时候就必胜。)

然后用RSolve查找通项。(←喂喂,这件事情好像比赛的时候没法干啊。)

131227-use-rsolve-to-find-expr.jpg

这就解决了我会说?

哦,对了,实际上我们要求的其实是f(n)

至于其他坑的地方,请见代码里面那多的不可直视的if else

AC代码:

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
//HDU 糖果大战 
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
double p,q;
double result2(int n,int m);
double result(int n,int m){
double lose=(p-1)*q;
double win=(q-1)*p;
double bi=lose/win;
if(fabs(bi-1)<1e-8) return result2(n,m);
else return (pow(bi,n)-1)/(pow(bi,m+n)-1);
}
double result2(int n,int m){
return (double)n/(n+m);
}
int main(int agrc, char *agrv[]){
int N,M;
while(cin>>N>>M>>p>>q){
if(N==0) cout<<"0.00"<<endl;
else if(M==0) cout<<"1.00"<<endl;
else if(fabs(p)<1e-8) cout<<"0.00"<<endl;
else if(fabs(q-1)<1e-8) cout<<"0.00"<<endl;
else if(fabs(p-q)<1e-8) printf("%.2fn",result2(N,M));
else printf("%.2fn",result(N,M));
}
return 0;
}

使用STL的prev_permutation生成组合数

今天碰到这么一个要求生成组合数的题目。其实前几天在果壳上就有人发过类似的题目,不过他那题其实是无解的。


题目简单说就是给你k个数,让你生成这k个数中取出6个所有的组合。要求按照数字升序排列。

输入每行第一个数为k,后面是k个数。如果k为0,则表示输入结束。

一般的思路是写一个递归程序——先生成k-1个数的组合数,再在后面添加上第k个数的所有情况。

不过会出点问题,就是不好排序。我曾经尝试着先把输出写进缓存,然后排序再输出。

但是这明显不是好的风格嘛。

就在这时我想到了STL的permutation函数。


在写果壳的看到的那题的时候,我了解到了有这么一个东西的存在,它能生成一组数据的全排列。

std::next_permutation(iterator begin, iterator end);std::prev_permutation(iterator begin, iterator end);

知道了这个东西之后,我还知道了STL并没有能够遍历生成组合数的东西。当时觉得十分不解。。。直到我知道了现在这种方法。


简单的说,我们用一个二进制序列来表示我们需要取出的元素。比如我们有15个元素,需要从中取6个。

我们可以把这个序列定义为111111000000000

其中1表示该元素取出,0表示该元素不取出。

如何遍历这个组合数呢?我们可以轻易发现所有的组合数刚好就是上面那个序列的全排列!

于是我们生成一个布尔值序列,并用STL的prev_permutation排列它。(←为什么不用next_permutation?其实自己试一下就知道了,当然是因为方向不一样,我这里要的是升序。)

然后这个序列中布尔值为真的地方,就是对应的目标序列中需要取出的元素。


最后,我还是会附上代码的:

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
#include <cstdio> 
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int S[140];
vector<bool> Serial;
void CombinationNumber(int n,int k){
Serial.clear();
for(int i=0;i<k;i++){
Serial.push_back(true);
}
for(int i=0;i<n-k;i++){
Serial.push_back(false);
}
do{
//int ZenMeNengGeShiCuoWuNe=0;
for(int i=0;i<n;i++){
if(Serial[i]){
cout<<S[i];
//ZenMeNengGeShiCuoWuNe++;
//if(ZenMeNengGeShiCuoWuNe!=k){
cout<<" ";
//}

}
}
cout<<endl;
}while(prev_permutation(Serial.begin(),Serial.end()));
}

int main(){
int k;
while(cin>>k){
if(k==0)break;
else{
for(int i=0;i<k;i++){
cin>>S[i];
}
}
CombinationNumber(k,6);
cout<<'n';
}
return 0;
}

此题在提交的时候还把我坑坏了,当然这个和本文主题无关,在此略过不表,具体来说可见代码中被注释掉的部分。

FeelyBlog更新——侧边栏动态化

虽然可能和之前的看不出区别,但是实际上区别还是很大的。

我实在不想承认,其实我之前的侧边栏是——静态的。。。。。。

好吧,从这个版本之后,侧边栏变成动态的了。这更方便了修改侧边栏内容。

事实上,由于侧边栏是静态的,所以我自从做好之后就再也没有改动过了。

之后的更新中, 我会把侧边栏编辑加入后台。

在我的想法中,侧边栏是这个网站唯一可以加入自定义HTML代码的地方。(←当然,我指的是通过后台加入。)


现在FeelyBlog正在准备以下的更新:

加入博文和评论删除功能。(←喂,连删除功能都没有真的大丈夫。)

加入侧边栏动态化后台编辑界面。

在特大屏幕上的显示效果会变得更好看一些。

后台草稿箱,以及支持Ctrl S保存到草稿箱和Ctrl Enter提交的设定。

嗯,其他的暂时还没想。(←不要问我顶栏的搜索功能。。。。那个我估计一时半会都不会写的。)


接下来还有很多的事情。

比如Namido Puzzle 5.0,我好像是第一次透露关于Namido Puzzle 5.0的动态。

是的,Namido Puzzle 5.0已经开始筹备了。我正在慢慢的写剧本。

希望能让Namido Puzzle 5.0变得好玩一些。

然后还有CCBC7。。。。。嗯嗯,这是个更好玩的东西。不过由于CCBC7我并不是负责人,它的进度是我不能控制的。

我其实特别希望CCBC7的筹备速度能快一点,不要像CCBC6的时候那样,我们都没有时间自己玩一下。。。。。。

自己玩一下的必要性还是很高的,比如可以发现Bug之类的东西。。


由于我们学校明年举办ACM-ICPC比赛,但是明显现在的集训队没有那么多队员。。。。。。于是我就被拉进去了。。

所以我的博客也会经常更新一些奇怪的东西。。

(←话说这个博客自从启用以来,还没有正式公开过呢。。。。)

又被long long坑了——三进制转换

我讨厌计算精度那么高的东西。 把输入的数转换为3进制,shuoj上的简单题。 写了个递归,每次把除三的余数存下来入栈,然后除三递归。 递归结束后出栈即可。 结果被long long坑到了。。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h> 
#include <math.h>

int st[100000],to=0;
void tobase3(long long n){
if(n>0){
st[to]=n%3;
to++;
tobase3(n/3);
}
}
int main(){
int i;
long long n;
while(~scanf("%lld",&n)){
to=0;
tobase3(n);
for(i=to-1;i>=0;i--){
putchar(st[i]+48);
}
printf("n");
}
return 0;
}

没有空白的C语言

其实我一直是对“滥用”C语言特性的行为十分感兴趣。虽然不属于正常的编程。只是作为程序猿的自娱自乐。。。

不过特别有意思的啊。。。

今天中午在校内OJ上刷了几道C语言基础题,题目仅仅是给那些C语言的新手做的。不过我加入了限制条件:不能用空白字符,包括空格,回车和Tab键。

C语言一下子变得有趣了有木有。

下面我把今天写的题目和代码贴上来:


题目1

Description

s=a+aa+aaa+aaaa+aa...a的值,其中a是一个一位的整数。 例如2+22+222+2222+22222(此时共有5个数相加)

Input

整数ann个数相加,1<= n, a<=9

Output

s的值

Sample Input

1
2 2 

Sample Output

1
24 

我的代码:

1
a,n,s,p,i;main(){scanf("%d%d",&a,&n);for(;i<n;i++){p=p*10+a;s+=p;}printf("%d",s);} 

题目2

Description

按如下递归公式求函数值。 x=1f(x)=10x>1f(x)=f(x-1)+2

Input

整型变量x

Output

f(x)

Sample Input

1
10 

Sample Output

1
28 

我的代码:

1
x;f(__typeof__(int)a,__typeof__(int)n){if(n<=0)return(0);if(n==1)return(a+10);return(f(a+2,n-1));}main(){scanf("%d",&x);printf("%d",f(0,x));} 

题目3

Description

求矩阵的两对角线上的元素之和

Input

矩阵的行数N ; 和一个N*N的整数矩阵a[N][N] (N<=10)

Output

所输矩阵的两对角线上的元素之和

Sample Input

1
2
3
4
5
6
7
3 

1 2 3

4 5 6

7 8 9

Sample Output

1
25 

我的代码:

1
n,a[10][10],u,i;void*s(){u=0;for(i=0;i%lt;n;i++){u+=a[i][i];u+=a[i][n-1-i];}return(0);}main(){scanf("%d",&n);for(;i<n;i++)for(u=0;u<n;u++)scanf("%d",&a[i][u]);s();if(n%2!=0)u-=a[n/2][n/2];printf("%d",u);} 

题目4

Description

求出1-N中的所有素数

Input

大于1的正整数N

Output

1-N中的所有素数,(以从小到大的格式输出)

Sample Input

1
9 

Sample Output

1
2 3 5 7 

我的代码:

1
n,b=1,i;p(__typeof__(int)a){while(1){a++;for(i=2;i<sqrt(a);i++)if(a%i==0)break;if(i>sqrt(a))return(a);}}main(){scanf("%d",&n);while((b=p(b))<n)printf("%d%c",b,0x20);} 

方法总结

  1. 基本思路

    • 标准库文件不需要#include导入,编译器会进行正确的猜测。
    • 没有定义类型的变量将被视为int类型。如果这个变量是全局变量,它会被初始化为0。
    • 没有定义返回类型的函数将被视为具有int返回类型。
    • C语言中运算符可以通过括号和后面的待运算数区分开。比如return 0;可以写成return(0);
  2. 消除变量定义空格

    • 默认变量为整数形式,直接在最前面定义为全局变量,这样不需要int a中间的空格,直接写为a即可。
    • 利用“ * ”:定义 【char*a,b;】这样引入了一个没用的指针a,但是可以不需要空格就定义char b
  3. 消除struct定义空格利用typedeftypedef int MT可以写作int typedef MT,(MT为自定义的数据类型)。

    使用类似这样的写法:

    1
    struct{int*n,*p,a,b;char*a,b;}typedef*MP,MT;

    这样你就有了一个名字为MTstruct,和一个名字为MPMT类型指针。(为什么要定义这个指针?请参照1.2)。

  4. 消除函数形参表中的空格

    最麻烦的可能在函数形参表这里。比如一个函数void fun(int a, int b);。如何去掉形参表中int a里的这个空格呢?

    只要使用typeof关键字即可。上边的函数可以定义作void*fun(typeof(int)a,typeof(int)b);

    但是当我今天把这样的代码提交到OJ上时,被判为CE。经查找资料而得,ISO C需要加上双下划线,写作:__typeof__(int)

  5. 字符串中的空格真的碰到字符串里面需要空格了。你只需要用0x20这个ASCII码值代替它就好了。就像我上边第4题的输出做的那样。