2009年4月8日星期三

继续暴力搜索,SGU 125

题目大意:有两个 NxN (N<=3) 的矩阵 A、B。1 <= A[i, j] <= 9,B[i, j] 表示 A 中与 A[i, j] 相邻的<=4个格子内比 A[i, j] 大的格子数。给出 B,求 A。

为什么叫作继续呢。。。。。我也不好多说了。。。。。结果是 23ms 的 AC,能排上第一页了,不错不错。。。


program sgu_125;
{$APPTYPE CONSOLE}
const
 NS = 'NO SOLUTION';
 
var
 N: Integer;
 i, j: Integer;
 a11, a12, a13, a21, a22, a23, a31, a32, a33: Integer;
 b11, b12, b13, b21, b22, b23, b31, b32, b33: Integer;

begin
 readln(N);
 if N = 1 then
  begin
   readln(a11);
   if a11 <> 0 then
    writeln(NS)
   else
    writeln(1)
  end
 else if N = 2 then
  begin
   readln(b11, b12);
   readln(b21, b22);
   for a11 := 1 to 9 do
    for a12 := 1 to 9 do
     for a21 := 1 to 9 do
      if ord(a21 > a11) + ord(a12 > a11) = b11 then
       for a22 := 1 to 9 do
        if ord(a11 > a12) + ord(a22 > a12) = b12 then
         if ord(a11 > a21) + ord(a22 > a21) = b21 then
          if ord(a12 > a22) + ord(a21 > a22) = b22 then
           begin
            writeln(a11, ' ', a12);
            writeln(a21, ' ', a22);
            readln;
            halt
           end;
   writeln(NS)
  end
 else
  begin
   readln(b11, b12, b13);
   readln(b21, b22, b23);
   readln(b31, b32, b33);
   for a11 := 1 to 9 do
    for a12 := 1 to 9 do
     for a21 := 1 to 9 do
      if ord(a12 > a11) + ord(a21 > a11) = b11 then
       for a22 := 1 to 9 do
        if ord(a12 > a22) + ord(a21 > a22) <= b22 then
         for a13 := 1 to 9 do
          if ord(a11 > a12) + ord(a13 > a12) + ord(a22 > a12) = b12 then
           for a31 := 1 to 9 do
            if ord(a11 > a21) + ord(a31 > a21) + ord(a22 > a21) = b21 then
             for a23 := 1 to 9 do
              if (ord(a12 > a13) + ord(a23 > a13) = b13) and
               (ord(a12 > a22) + ord(a21 > a22) + ord(a23 > a22) <= b22) then
               for a33 := 1 to 9 do
                if ord(a13 > a23) + ord(a22 > a23) + ord(a33 > a23) = b23 then
                 for a32 := 1 to 9 do
                  if (ord(a22 > a32) + ord(a33 > a32) + ord(a31 > a32) = b32) and
                   (ord(a12 > a22) + ord(a21 > a22) + ord(a23 > a22) + ord(a32 > a22) = b22) and
                   (ord(a32 > a31) + ord(a21 > a31) = b31) and
                   (ord(a32 > a33) + ord(a23 > a33) = b33) then
                   begin
                    writeln(a11, ' ', a12, ' ', a13);
                    writeln(a21, ' ', a22, ' ', a23);
                    writeln(a31, ' ', a32, ' ', a33);
                    halt
                   end;
   writeln(NS)
  end
end.

2009年4月1日星期三

URAL 1127

小岛叫我做下,说不好做,可惜10分钟就ac了。。。时间空间复杂度都极小。。。至于其中缘由,见下程序。。。。。。。。。
题目大致意思是给你一些相同大小的正方体,每个正方体六个面上涂有不同颜色,选一些正方体堆成一个 1x1xK 的塔,要求前后左右四个面必须分别是一种颜色,问 K 最大为多少。

既然有人问了,就说明下,Q[a, b, c, d] 表示四个面颜色为 a、b、c、d (顺时针或逆时针)时的 K 的最大值。


program ural_1127;
const
 Front = 1;
 Right = 2;
 Left  = 3;
 Rear  = 4;
 Top  = 5;
 Bottom = 6;
var
 Ans, N: Longint;
 i, j, k, l: Longint;
 Q: array [1..10, 1..10, 1..10, 1..10] of Longint;
 D: array [1..6] of Longint;
 C: Char;

begin
 fillchar(Q, sizeof(Q), 0);
 readln(N);
 for i := 1 to N do
  begin
   for j := 1 to 6 do
    begin
     read(C);
     case C of
      'A': D[j] := 1;
      'B': D[j] := 2;
      'C': D[j] := 3;
      'G': D[j] := 4;
      'O': D[j] := 5;
      'R': D[j] := 6;
      'S': D[j] := 7;
      'V': D[j] := 8;
      'W': D[j] := 9;
      'Y': D[j] := 10
     end
    end;
   readln;
   // Front - Right - Rear - Left
   inc(Q[D[Front], D[Right], D[Rear], D[Left]]);
   inc(Q[D[Right], D[Rear], D[Left], D[Front]]);
   inc(Q[D[Left], D[Front], D[Right], D[Rear]]);
   inc(Q[D[Rear], D[Left], D[Front], D[Right]]);
   
   inc(Q[D[Left], D[Rear], D[Right], D[Front]]);
   inc(Q[D[Rear], D[Right], D[Front], D[Left]]);
   inc(Q[D[Right], D[Front], D[Left], D[Rear]]);
   inc(Q[D[Front], D[Left], D[Rear], D[Right]]);
   
   // Front - Top - Rear - Bottom
   inc(Q[D[Front], D[Top], D[Rear], D[Bottom]]);
   inc(Q[D[Top], D[Rear], D[Bottom], D[Front]]);
   inc(Q[D[Bottom], D[Front], D[Top], D[Rear]]);
   inc(Q[D[Rear], D[Bottom], D[Front], D[Top]]);

   inc(Q[D[Bottom], D[Rear], D[Top], D[Front]]);
   inc(Q[D[Rear], D[Top], D[Front], D[Bottom]]);
   inc(Q[D[Top], D[Front], D[Bottom], D[Rear]]);
   inc(Q[D[Front], D[Bottom], D[Rear], D[Top]]);
   
   // Left - Top - Right - Bottom
   inc(Q[D[Left], D[Top], D[Right], D[Bottom]]);
   inc(Q[D[Top], D[Right], D[Bottom], D[Left]]);
   inc(Q[D[Bottom], D[Left], D[Top], D[Right]]);
   inc(Q[D[Right], D[Bottom], D[Left], D[Top]]);

   inc(Q[D[Bottom], D[Right], D[Top], D[Left]]);
   inc(Q[D[Right], D[Top], D[Left], D[Bottom]]);
   inc(Q[D[Top], D[Left], D[Bottom], D[Right]]);
   inc(Q[D[Left], D[Bottom], D[Right], D[Top]])
  end;
 Ans := 0;
 for i := 1 to 10 do
  for j := 1 to 10 do
   for k := 1 to 10 do
    for l := 1 to 10 do
     if Q[i, j, k, l] > Ans then
      Ans := Q[i, j, k, l];
 writeln(Ans)
end.

2009年3月30日星期一

市赛

可能我们这边比较怪吧,联赛之后还需要搞个市赛选出市队

昨天就在现在这个机房比完了,题目很水,没有原创题,打字也浪费时间,就不贴了。本来感觉不是很理想,有一道很简单的 dp 题没想出来,只交了个贪心。
但是现在出来的是我是满分,于是乎我便不再担心自己

但是很多同学的命途多舛啊

squll,本来说是 310 的,还是很有希望,今天再对了下是 240,唉。。。其实他靠这样差,我也有点过失,考试前我还让他看看 hlpp,但最大流这种东西市赛是根本不可能涉及的。然后考试的时候忘记提醒他细心了,结果第三题他少考虑了一些情况,于是就悲剧了。

作为学长的确考试之前我应该提醒高一同学仔细读题的,结果我却没有做到这样的责任。今天各人看了下程序,有两个人高精度写错,一个人犯把 i 打成 j 的低级错误,一个人没有按照要求少输出了解数……

无语

离开这个自己喜欢的“事业”,是很难受的一件事吧?

既然如此,还是努力奋斗吧

真的希望所有人都能早点将大学定掉,学得轻松点,玩得开心点

但是,唉。。。

也许高二之后就我跟小岛两个人了吧。。。。。。。

Bless everyone

2009年3月24日星期二

段考挂蛋

目前出来一门,数学65,刚刚过了64.8的平均分....
语文还好那个传说中作文8分的人不是我....
生物对了下选择题+第一个大题大概-15......

悲壮啊



还好rqnoj现在第二了
刷到第一之后把所有算法复习一遍...

2009年3月22日星期日

又上rq,发了篇题解

无聊中看到某人的恐怖分子的题解
居然是硬枚举 s、t,o(N^5) 啊。。。。。。
于是就又写个了 Stoer-Wagner 算法介绍。。。。。。
这里原文照抄下吧。。。


其实话说我一开始也是最大流做滴。。。最大流即使是用hlpp也要 o(n^4) 的复杂度,要像某个题解说的枚举 s、t 就到 o(n^5) 了。。而且hlpp也不是随随便便就能写出来滴。。。

不过看清本质之后,这一题本质就是求无向图的全局最小割,这其实是有专门算法的,叫 Stoer-Wagner 算法,复杂度不超过 o(N^3),而且代码行数很短。。真的很短

下面概略说明下算法,正确性证明略去:

首先我们定义对于不存在的边 (u,v),w[u, v] = 0。
之后介绍经典的 Contract(a, b) 操作:
加入新点 u,对于 a、b 之外的每个点 v,加入无向边 (u, v) 并令 w[u, v] = w[a, v] + w[b, v]
完成之后删除 a、b 两点及相关联的所有边
不难看出,每做一次 Contract 操作,图的节点数减少1

Stoer-Wagner 算法的正确性基于如下定理:
一个无向图的全局最小割,等于这个图的 s-t 最小割,或对这个图进行 Contract(s, t) 得到的图的全局最小割。

定理是显然的,下面我们说明如何求无向图的 s-t 最小割:

首先定义对于点集 A 和点 u,w[A, u] 表示 A 中所有点与 u 连边的权值之和。再次说明,不存在的边视为0处理。
1. 初始化点集 A={}
2. 任意取一点 a 加入 A 中
3. 每次取 w[A, u] 最大的点 u,将其加入 A,直到 A=V
4. 可取3中倒数第二次加入的点为 s,倒数第一次加入的点为 t(无向图顺序无关紧要),则对应的 s-t 最小割为 w[U-{t}, t]

证明可以用数学归纳法,大家自己试试吧^_^

不难看出,上述 s-t 最小割算法的朴素实现是 O(N^2) 的(第三步显然还可以用最大堆优化,达到更好的时间界),而对于一个图,Contract 操作最多进行 n-1 次(此时图中只剩1个点了)。所以算法的复杂度不超过 O(N^3)

而代码行数,可想而知有多短了。。。

而且即使写错了什么,调试起来也比调试hlpp轻松多了


题目:

一个国家由n个城市组成,任意两个城市间都有一条双向的道路。如今,恐怖分子想要炸掉其中的一些道路,使得这n个城市变得不再连通,也就是说,存在至少两个城市,它们之间不可通过道路互相到达。要炸毁一条道路需要一定的代价。请你计算一下要使恐怖分子达到它们的目的,所需要的最小总代价是多少。

2009年3月20日星期五

段氏恒等式照片一张

废话不多说,先上照片,早上亲照:


(这一次照片质量出奇的好,可能是班级光线充足的缘故)
前两次都没机会照下来,很遗憾,不过这次终于抓住机会拍了下来 ^_^ 谨留作纪念

还是写写东西吧...

发觉这个blog有很长时间没有写过东西了,现在决定还是好好利用起来吧
blog不必要像所谓空间那样,弄得花里胡哨,简洁就好
下周1、2段一,基本可以确定要挂蛋
下周日在本校市赛,估计问题不会很大。这两天打算不钻难题了,去vijos做点水题找找自信,同时晚上睡早些,补补最近一直不怎么样的精神状态。
准备今天晚上做个图论的小总结,把我了解的一些图论结构及算法都总结一下,尽量总结全一些,临考复习也方便些。
大概就这样吧。。。。这里还是真的要利用起来,不能浪费了 google 的服务啊……

2008年10月21日星期二

NOIP初赛险峻飘过~准备复赛中

RT,这一次初赛的 RP 貌似还是比较低,初分倒数第五勉强飘过。唯一的庆幸是倒数第五这个名次已经不可能被查分的人挤掉了。。。

准备复赛中-_-

2008年10月17日星期五

NOIP 2008 明天初赛,回归~

明天 NOIP 2008 就初赛了
虽然没有什么悬念,不过qq上某人的留言再次让我想到了这里
一切都是那么平静,很自然。

明天就初赛了,大家加油、保重。

运动会我们班表现也不错,拿了一个第一和一个第三,加上稿子估计也有20多分了吧,希望能获得个好名次。

就写这么多吧,以后这个blog还是要好好利用起来,就算是当个日记本也是好的 ^_^

总而言之,大~家~共~同~进~步~

2008年8月12日星期二

又一次诡异的终结

明天就要上学去了呢
寄宿制学校就这点不好,估计将有两三个星期碰不了电脑了
今天又错过一场 TJU 上一场比赛,好像还是有一定难度,可惜!哪天抽空把题做一下吧。
唯一可喜可贺的是今天终于在 coLinux 上成功降级 KDE4 到 KDE 3.5.6,另外 Xming 也调试成功了,也在新的环境下玩了一把 Konquest,感觉速度很好,几乎等同于本地环境,不知道是不是心理作用。
不过对 OpenGL 的应用来说 Xming 还是很差劲,对 OpenGL 的支持仅仅停留在对微软垃圾 OpenGL 驱动的封装上。我本想在 Windows 下体验一把 chromium 和 supertuxkart,结果是 chromium 巨卡无比(基本上是 5fps 的速度),supertuxkart 启动后窗口内一片漆黑,并且无法关闭。在 coLinux 终端内直接 Ctrl-Z 之后,那个窗口还是没有消失。最后只能重新启动 Xming。
看来想在 Windows 下跑 Linux 还是长路漫漫啊,不过至少 KDE 是可以无缝运行了,等到哪天有空尽量把 LaTeX 和 Kile 编译好(我编译 IceWeasel 用了近一个小时,编译这两个东西估计又得放在晚上了),这样之后就可以随意移动我的工作环境了。

不过 9 月正式开学之前可能要先丢下 Linux 和 OI 一段时间了 :-(

2008年8月1日星期五

趣题:输出自己代码的程序

考虑这样一个问题:编写一个高级语言程序,能在不访问所有外界数据的情况下,直接输出它本身的源代码,这个输出必须和程序源代码完全相同。


















====================================
初看起来,这怎么可能呢?但这样的程序的确是存在的。比如,下面这个 Pascal 程序就可以做到:


const a='const a=';b=';begin write(a,#39,a,#39#59#98#61#39,b,#39,b)end.';begin write(a,#39,a,#39#59#98#61#39,b,#39,b)end.



这个还算比较简单的,还有更牛*的(删掉换行):


program s;const bbb='program s;const bbb';a='a';b='b';bb=');writeln(';
aa='''';ab='=''';ba=''';';
aaa='begin writeln(bbb,ab,bbb,ba,a,ab,a,ba,b,ab,b,ba,b,b,ab,bb,ba';
aba='a,a,ab,aa,aa,ba,a,b,ab,ab,aa,ba,b,a,ab,aa,ba,ba';
abb='a,a,a,ab,aaa,ba);writeln(a,b,a,ab,aba,ba);writeln(a,b,b,ab,abb,ba';
baa='b,a,a,ab,baa,ba);writeln(b,a,b,ab,bab,ba);writeln(aaa,bb';
bab='aba,bb);writeln(abb);writeln(bb,baa);writeln(bb,bab)end.';
begin writeln(bbb,ab,bbb,ba,a,ab,a,ba,b,ab,b,ba,b,b,ab,bb,ba);writeln(
a,a,ab,aa,aa,ba,a,b,ab,ab,aa,ba,b,a,ab,aa,ba,ba);writeln(
a,a,a,ab,aaa,ba);writeln(a,b,a,ab,aba,ba);writeln(a,b,b,ab,abb,ba
);writeln(b,a,a,ab,baa,ba);writeln(b,a,b,ab,bab,ba);writeln(aaa,bb
);writeln(aba,bb);writeln(abb);writeln(bb,baa);writeln(bb,bab)end.


C++ 版本:

#include
main(){char*s="#include%cmain(){char*s=%c%s%c;cout.form(s,10,34,s,34,10);}%c";cout.form(s,10,34,s,34,10);}


BrainF**k 版本:

>>+++++++>>++>>++++>>+++++++>>+>>++++>>+>>+++>>+>>+++++>>+>>++>>+>>++++++>>++>>++++>>+++++++>>+>>+++++>>++>>+>>+>>++++>>+++++++>>+>>+++++>>+>>+>>+>>++++>>+++++++>>+>>+++++>>++++++++++++++>>+>>+>>++++>>+++++++>>+>>+++++>>++>>+>>+>>++++>>+++++++>>+>>+++++>>+++++++++++++++++++++++++++++>>+>>+>>++++>>+++++++>>+>>+++++>>++>>+>>+>>+++++>>+>>++++++>>+>>++>>+>>++++++>>+>>++>>+>>++++++>>+>>++>>+>>++++++>>+>>++>>+>>++++++>>+>>++>>+>>++++++>>+>>++>>+>>++++++>>++>>++++>>+++++++>>+>>+++++>>+++++++>>+>>+++++>>+>>+>>+>>++++>>+>>++>>+>>++++++>>+>>+++++>>+++++++>>+>>++++>>+>>+>>++>>+++++>>+>>+++>>+>>++++>>+>>++>>+>>++++++>>+>>+++++>>+++++++++++++++++++>>++>>++>>+++>>++>>+>>++>>++++>>+++++++>>++>>+++++>>++++++++++>>+>>++>>++++>>+>>++>>+>>++++++>>++++++>>+>>+>>+++++>>+>>++++++>>++>>+++++>>+++++++>>++>>++++>>+>>++++++[<<]>>[>++++++[-<<++++++++++>>]<<++..------------------->[-<.>>+<]>[-<+>]>]<<[-[-[-[-[-[-[>++>]<+++++++++++++++++++++++++++++>]<++>]<++++++++++++++>]<+>]<++>]<<[->.<]<<]


Befunge 版本:

:0g,:93+`#@_1+



这样的程序被称作“自展”程序(不是自展编译器-_-),http://www.nyx.net/~gthompso/quine.htm 这个网站上提供了各种语言大量的自展程序,大家闲暇时候可以去看看 ^_^

2008年7月30日星期三

RQNOJ 上三道几乎没人过的题目的题解

废话:RQNOJ 上水题真不少啊,不过难题还是有一些的(不然就没有本文了-_-)

下面开始题解:

P60. 美丽的中国结

题目背景
kitty刚刚高三毕业.看到同学们都回家的回家,旅游的旅游,她的心里有些落寞.英俊潇洒风流倜傥迷倒万千KL却仅对kitty感冒的fish看在眼里,急在心里.一天,fish提出和kitty两个人一起外出旅游.kitty犹豫了几天,想好能瞒过家长的理由后(要问是什么……自己猜去),答应了.fish很高兴地带着kitty去登记了(别想歪,登记旅游团而已……),日照青岛五日游.当然啦,他们玩得很高兴.虽然这次旅行是fish先提议的,但kitty因为玩得很畅快(刚高考完嘛),所以想送给fish一份礼物,一份能让见多识广的fish都无法忘怀的礼物.她从路边 9¾站台的某算命先生那里得知中国结具有增加RP的效果,而这正是fish所需要的,因此她决定动手给fish编一个奇特的中国结.

题目描述
中国结形式多样,fish会喜欢什么样的呢?思考几天后,kitty决定给fish编一个树状的中国结.这个中国结有n个结点(编号1,2,…,n),这n个结点之间总共恰有n-1条线相连,其中结点1上是树的根.这是一个奇特的中国结,因此它的编织方式也很奇特.在编织过程中的每一步骤,kitty有时需要将一个结点子树里的所有结点i的状态全部取反(如果原来结点i已经打结,则解开i,否则将结点i打结),有时又需要知道一个结点的子树里有多少已经打结的结点,你能帮助可爱的kitty完成这份礼物吗?

数据规模
对于40% 的数据,1≤n≤10000, 1≤m≤20000
对于100%的数据,1≤n≤100000, 1≤m≤100000

输入格式
输入第一行有个整数n,表示这个中国结有n个结点以下n-1行,每行有两个整数u和v(1≤u,v≤n),表示结点u和v间有一条线相连;再一行有个整数m,表示kitty要进行的步骤数以下m行,每行可能为:"C x":表示将结点x的子树中所有结点的状态取反(包括x)或"Q x":表示kitty想知道结点x的子树中有多少已经打结的结点(包括x)

输出格式
对于每个“Q x”输出一行整数,表示结点x的子树中有多少已经打结的结点(包括x)

样例输入
5
1 2
1 3
2 4
2 5
5
Q 1
C 1
Q 1
C 2
Q 1

样例输出
0
5
2

题解
这是 MM 群七夕模拟赛的一道题(这个模拟赛题目质量很高,建议一做),看到如此大数据范围的询问题,大家的第一反应肯定就是——这是一道数据结构题。的确,本题考的是线段树的操作。

我们对题目中的树进行一次 DFS,将遍历的顺序记录在线段树(下面简记作 A[])中,并记录每个树节电进入和离开时在线段树中的位置(下面简记作 St[x] 和 End[x]),这样原题目中的树便映射到了我们定义的线段树上了。

后面就比较简单了,我们在每个线段树节电记录一个域:state[x](节电状态)、sum[x](子树打结数),题目中的两个操作即是对线段树作如下操作:

C x:
state[St[x]..End[x]] 全部取反

Q x:
询问 sum[St[x]..End[x]]

我采用的数组模拟线段树,空间复杂度 O(n),时间复杂度 O(nlgn)

参考程序
注意:程序中用到自己实现的栈是因为在 RQNOJ 上提交时直接递归的 dfs 会栈溢出,调内存也没调好(现在想想可能是当时指令错了),于是我就自己模拟实现了一个栈。


program p60(input, output);
const
maxn = 100000;

var
ch, ch2: char;
First, Last, Next, E: array [0..maxn * 2] of longint;
StartPos, EndPos: array [1..maxn] of longint;
Sum: array [1..maxn * 4] of longint;
Visited: array [1..maxn] of boolean;
Sign: array [1..maxn * 4] of boolean;
STPoint, LL, RR, Answer, Len, EdgeCount, u, v, n, m, i: longint;
List: array [1..maxn] of record
u, q: longint
end;
flag: boolean;

procedure addEdge(u, v: longint);
begin
inc(EdgeCount);
Next[Last[u]] := EdgeCount;
Last[u] := EdgeCount;
E[EdgeCount] := v;
if First[u] = 0 then
First[u] := EdgeCount
end;

procedure Maintain(k, l, r: longint);
var
mid, lc, rc: longint;

begin
if Sign[k] then
begin
Sign[k] := false;
if l < r then
begin
lc := k shl 1;
rc := lc + 1;
mid := (l + r) shr 1;
Sign[lc] := not sign[lc];
Sign[rc] := not sign[rc];
Sum[lc] := mid - l + 1 - Sum[lc];
Sum[rc] := r - mid - Sum[rc]
end
end
end;

procedure Change(k, l, r: longint);
var
mid: longint;

begin
if (LL <= l) and (r <= RR) then
begin
Sign[k] := not Sign[k];
Sum[k] := r - l + 1 - Sum[k]
end
else
begin
mid := (l + r) shr 1;
Maintain(k, l, r);
if LL <= mid then
Change(k shl 1, l, mid);
if mid + 1 <= RR then
Change(k shl 1 + 1, mid + 1, r);
Sum[k] := Sum[k shl 1] + Sum[k shl 1 + 1]
end
end;

procedure Question(k, l, r: longint);
var
mid: longint;

begin
if (LL <= l) and (r <= RR) then
inc(Answer, Sum[k])
else
begin
mid := (l + r) shr 1;
Maintain(k, l, r);
if LL <= mid then
Question(k shl 1, l, mid);
if mid + 1 <= RR then
Question(k shl 1 + 1, mid + 1, r)
end
end;

procedure Push(uu, qq: longint);
begin
inc(STPoint);
with List[STPoint] do
begin
u := uu;
q := qq
end
end;

procedure Pop;
begin
dec(STPoint)
end;

begin
fillchar(First, sizeof(First), 0);
fillchar(Last, sizeof(Last), 0);
fillchar(Next, sizeof(Last), 0);
fillchar(Visited, sizeof(Visited), 0);
fillchar(Sign, sizeof(Sign), 0);
fillchar(Sum, sizeof(Sum), 0);
EdgeCount := 0;
readln(n);
for i := 1 to n - 1 do
begin
readln(u, v);
addEdge(u, v);
addEdge(v, u)
end;
STPoint := 0;
Push(1, First[1]);
Visited[1] := true;
Len := 1;
StartPos[1] := Len;
while STPoint > 0 do
with List[STPoint] do
begin
flag := false;
while q > 0 do
if not Visited[E[q]] then
begin
Push(E[q], First[E[q]]);
Visited[E[q]] := true;
inc(Len);
StartPos[E[q]] := Len;
q := Next[q];
flag := true;
break
end
else
q := Next[q];
if not flag and (q = 0) then
begin
EndPos[u] := Len;
Pop
end
end;
readln(m);
for i := 1 to m do
begin
read(ch);
read(ch2);
readln(u);
LL := StartPos[u];
RR := EndPos[u];
if ch = 'C' then
Change(1, 1, n)
else
begin
Answer := 0;
Question(1, 1, n);
writeln(Answer)
end
end
end.


P113. 聪明的猴子

题目描述
在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的不同树冠上来回穿梭,以找到喜欢吃的果实。 现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树的坐标都不相同)。 在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到对面的树上。

【问题】
现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。

输入格式
第1行为一个整数,表示猴子的个数M(2<=M<=500); 第2行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1--1000之间); 第3行为一个整数表示树的总棵数N(2<=N<=1000); 第4行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000--1000)。 (同一行的整数间用空格分开)

输出格式
包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数。

样例输入
4
1 2 3 4
6
0 0
1 0
1 2
-1 -1
-2 0
2 2

样例输出
3

题解
这一题实际上是一道很基础的算法题,至于很少有人做出的原因很可能是题目未读懂。我们先来简单分析一下题意。

先对单一猴子进行考虑,我们将树网(暂且这么说吧)当作图中的节点,跳遍全部树即表示整个图连通。显然,这是一个平面图。那么跳遍这个平面图的节点所需要的跳跃距离至少是多少呢?

相信读者已经看出来了,这正是其最小生成树中最大边的长度!证明是很容易的,这里就不加赘述。

算法在实现时,我们首先计算出任意两树之间的距离,再使用 Kruskal 算法计算出最小生成树的最大边劝,再逐个比较每个猴子的跳跃距离即可。算法空间复杂度 O(n^2),时间复杂度 O(n^2+m)。

当然求平面图的最小生成树还有更快的算法,这里略去。

参考程序
program p113(input, output);
const
maxm = 500;
maxn = 1000;

var
Count, sum, m, n, i, j, k: longint;
monkey: array [1..maxm] of longint;
tree: array [1..maxn] of record
x, y: longint
end;
Edge: array [1..maxn * maxn] of record
a, b: longint;
Length: extended
end;
ufs, size: array [1..maxn] of longint;
ma: extended;

function findset(u: longint): longint;
begin
if ufs[u] = 0 then
exit(u)
else
begin
ufs[u] := findset(ufs[u]);
exit(ufs[u])
end
end;

procedure union(a, b: longint);
var
u, v: longint;

begin
u := findset(a);
v := findset(b);
if size[u] <> s do
dec(j);
if i <= j then
begin
tt := Edge[i].Length;
Edge[i].Length := Edge[j].Length;
Edge[j].Length := tt;
t := Edge[i].a;
Edge[i].a := Edge[j].a;
Edge[j].a := t;
t := Edge[i].b;
Edge[i].b := Edge[j].b;
Edge[j].b := t;
inc(i);
dec(j)
end
until i > j;
if j > left then
qsort(left, j);
if i <> b then
exit(a)
else
exit(b)
end;

procedure Kruskal;
var
i, cc: longint;

begin
ma := 0;
cc := 0;
for i := 1 to Count do
if findset(Edge[i].a) <> findset(Edge[i].b) then
begin
ma := max(ma, Edge[i].Length);
union(Edge[i].a, Edge[i].b);
inc(cc);
if cc = n - 1 then
break
end
end;

begin
fillchar(ufs, sizeof(ufs), 0);
fillchar(size, sizeof(size), 0);
readln(m);
for i := 1 to m do
read(monkey[i]);
readln(n);
for i := 1 to n do
with tree[i] do
readln(x, y);
Count := 0;
for i := 1 to n - 1 do
for j := i + 1 to n do
begin
inc(Count);
with Edge[Count] do
begin
a := i;
b := j;
Length := sqrt(sqr(tree[i].x - tree[j].x) + sqr(tree[i].y - tree[j].y))
end
end;
qsort(1, Count);
Kruskal;
sum := 0;
for i := 1 to m do
if monkey[i] >= ma then
inc(sum);
writeln(sum)
end.

P218. 奥运手拉手

题目描述
奥运会即将来临,为了迎接奥运会,Wish 和同伴们一起进行了一场名叫“奥运手拉手”的游戏。这个游戏的规则是这样的:
1. Wish 和朋友们在一起共有 n 个人
2. 这 n 个人围坐一圈,从某一个人开始顺时针编号为 1-n
3. 从第一个人开始报数,每次从 1 开始报,每报到 m,就让那个人出列,然后继续从 1 开始报数
4. n - 1 个人出列后,最后留在圈中的那个人获得胜利
Wish 很想赢得游戏,而且,他认为特定位置的出列次序应该有某种数学上的联系,为了验证他的猜想,他需要一些实际的数据。但是众所周知 Wish 是个大大大菜鸟,他只会朴素的模拟,对于较大的 n 和 m 无法得出答案,于是他找到了参加信息学竞赛的你,你可以帮助他吗?

数据规模
1 <= m <= n <= 200000
0 <= k <= 1000

输入格式
第一行三个数:n, m, k第二行至第 k + 1 行:每行一个数 ai

输出格式
共 k + 1 行第一行一个数 d,为最后出列的人在游戏开始时的编号第二行至第 k + 1 行,每行一个数 bi,表示第 ai 个人在第 bi 轮报数时出列

题解
我都不好意思说这是难题了…………-_-,大家都知道这是 Josephus 问题,但是为什么都不会呢。。。。。。这一题我不想写题解,只帖上程序了。

参考程序


program p202(input, output);
const
maxn = 200000;

var
n, m, k, head, i, j, d, count: longint;
key, left, right, size: array [0..maxn] of longint;
List: array [1..maxn] of longint;

procedure MakeTree(const l, r, current: longint);
var
mid: longint;

begin
mid := (l + r) shr 1;
key[current] := mid;
if mid > l then
begin
inc(count);
left[current] := count;
MakeTree(l, mid - 1, count)
end
else
left[current] := 0;
if mid < r then
begin
inc(count);
right[current] := count;
MakeTree(mid + 1, r, count)
end
else
right[current] := 0;
size[current] := size[left[current]] + size[right[current]] + 1
end;

function select(const t, k: longint): longint;
begin
if k = size[left[t]] + 1 then
select := key[t]
else if k <= size[left[t]] then
select := select(left[t], k)
else
select := select(right[t], k - size[left[t]] - 1)
end;

function delete(var t: longint; const k: longint): longint;
begin
dec(size[t]);
if (key[t] = k) or ((k < key[t]) and (left[t] = 0)) or ((k > key[t]) and (right[t] = 0)) then
begin
delete := key[t];
if (left[t] = 0) or (right[t] = 0) then
t := left[t] + right[t]
else
key[t] := delete(left[t], key[t] + 1)
end
else
if k < key[t] then
delete := delete(left[t], k)
else
delete := delete(right[t], k)
end;

begin
size[0] := 0;
readln(n, m, k);
count := 1;
MakeTree(1, n, 1);
j := 0;
head := 1;
for i := 1 to n do
begin
j := (j + m - 1) mod (n - i + 1) + 1;
d := select(head, j);
dec(j);
delete(head, d);
List[d] := i
end;
writeln(d);
for i := 1 to k do
begin
readln(d);
writeln(List[d])
end
end.



PS:大家看到这么多的标程,请一定保重。。。。

2008年7月29日星期二

此博客重新启动

原本的网站空间(http://www.wssnow.com/)在 7/27 到期了,目前也懒得续费,同时也没有去年暑假那么多时间来写 Web Application 了,就暂且用 blogger 来写写东西吧。

PS:在到期那天我随意放上去的论坛中莫名奇妙地出现了一个名叫 binarie(From RQNOJ, http://www.rqnoj.cn/)的用户,还发了一帖……汗……当时我的第一感觉时,你小子真行,google 还没更新缓存就都被你找到了……………………

Gentoo in coLinux 命令行环境全新安装成功!附送安装配置全过程

昨天晚上做了 N 题后开始进入无所事事期,前天调试 LFS 让人很窝火,2.6.25 内核的 reiser4 补丁怎么都 patch 不上,每次输入命令后命令行就停住不动了,前面装 Linux API Headers 还好好的啊!其他有的包也出现过类似问题,但我把包和 patch 从本地的 vfat 分区(主要是因为我是用迅雷下载的包,所以存在 Win32 分区内)复制到 /mnt/lfs/sources/ 下,再 tar + patch 就 ok 了,同样的方法在内核上却又不管用,很不解……………………这个问题,也希望有高手帮忙……………………(另注:我用的是 LFS BOOK 的 SVN 版本,地址:http://www.linuxfromscratch.org/lfs/view/development/)

好了~闲话少说(貌似我是个很喜欢说闲话的人 ;) ),下面步入正题,昨天在网上搜索 Linux on Windows 时,排除掉很多垃圾文章之后,第一页的 cygwin 首先映入眼帘,不过这东西真的很恶心,直接无视掉,然后翻到第二页,当我那龟网慢慢地开启这个不到 10k 的搜索页面时,一个叫 coLinux 的东东出现在我的视野中,打开一看发现乖乖这东西不得了,是一个可以在 Windows x86 系统上使用的 UML(User Mode Linux)!!!(这段貌似又是废话,表pia我,下面一定转入正题……;……;……;……;)

首先介绍一下 UML 是什么东西,顾名思义,User Mode Linux 即用户模式 Linux(众人:废话),也就是可以在已有的内核基础之上运行的内核,这个功能本来只是为了 Linux 下可以动态控制使用内核,现在已经被移植到 Windows 下,成为饶过虚拟机而使用 Linux 的一套高效率解决方案。

下面RT一下,附上我在 Windows XP 下基于 coLinux 全新安装 Gentoo Linux 的全过程:

1. 下载安装 coLinux 0.73(废话),http://www.colinux.org/ 上面自己找吧,sf 的服务器

2. 从 sf 文件列表中下载一个 gentoo 的包,新旧随意,它只是用来安装 Linux 的 host,如果网速较慢的话就选个最小的下载吧。

3. 解压缩下载的 gentoo 包,注意:这一个一两百兆的包解压后就是几个G,建议解到 NTFS 分区中并启用压缩,既可以节省大量空间,也可以避免你看见 CPU 爆满听见硬盘狂转……

4. 找一个能用的 dd(我用的是 cygwin 里的),使用下列指令(假设我们用gentoo_root作为文件系统文件):

dd if=/dev/zero bs=1k count=8M > gentoo_root

这样就可以创建一个 8G 的空白文件系统。这次就不要压缩了,NTFS 的压缩性能对性能影响比较大呵呵。

注意,本文假定上述三个东东都在一个目录下,若不是请自行修改目录。

5. 修改 gentoo.conf(您可能需要修改相关的目录设置),加入下面一行来载入我们刚刚创建的文件系统:
cobd2=gentoo-root

6. 双击 gentoo.bat (您可能需要先酌情修改)启动 gentoo host,默认用户名 root 密码 root,进入之后运行下列指令初始化和挂载目标分区:
$ mkreiserfs /dev/cobd2(可能需要 emerge reiserfsprogs,如果使用 ext2 或者 ext3 文件系统的话就用 mkext2fs 和 mkfs.ext3)
$ mkdir -v /mnt/gentoo
$ mount -v /dev/cobd2 /mnt/gentoo

这样就挂载完成了。之后上 gentoo.org 找个 mirror 下载 stage3 和 portage 树的 tarball(不用痛苦用 links 了,这次可以直接用 IE 了):

$ wget http://....../.../stage3-i686-2008.0.tar.bz2
$ wget http://....../.../portage-2008.0.tar.bz2
$ tar -xvjf stage3-i686-2008.0.tar.bz2 -C /mnt/gentoo/
$ tar -xvjf portage-2008.0.tar.bz2 -C /mnt/gentoo/usr/

7. 之后的安装就可以从 gentoo 官方手册的第六节开始进行了,注意不需要安装 kernel 和 bootloader。作为一个完整的安装手记,这里也大概写一下安装过程。

$ emerge mirrorselect
$ mirrorselect -i -o >> /mnt/gentoo/ect/make.conf
#选择一个合适的 mirror,注意不要选择 ipv6 站点
$ mirrorselect -i -r -o >> /mnt/gentoo/etc/make.conf
#选择一个合适的 rsync 服务器
$ cp -L /etc/resolv.conf /mnt/gentoo/etc/resolv.conf
$ mount -t proc none /mnt/gentoo/proc
$ mount -o bind /dev /mnt/gentoo/dev

这样配置后就可以 chroot 进去了,host 的历史使命基本完成 ;)
$ chroot /mnt/gentoo
$ env-update
$ source /etc/profile
$ export PS1="(chroot env) $PS1"

接下来更新 portage 树:
$ emerge --sync

这个工作耗掉我一下午时间(额,数学一本暑假作业就这样做完了,我的手啊……)

设置 glibc locale:
$ nano /etc/locale.gen
加入:
en_US ISO-8859-1
en_US.ISO-8859-1 ISO-8859-1
en_US.UTF-8 UTF-8
zh_CN GBK
zh_CN.GBK GBK
zh_CN.GB2312 GB2312
zh_CN.GB18030 GB18030
zh_CN.UTF-8 UTF-8
zh_TW BIG5
zh_TW.BIG5 BIG5
zh_TW.UTF-8 UTF-8

$ locale-gen

编辑 /etc/fstab:
$ nano /etc/fstab
修改 ROOT 为 cobd0,并做其他相关配置,如果你增加了交换分区也请在这里配置

$ nano /etc/conf.d/hostname
设置 HOSTNAME 主机名
$ nano /etc/conf.d/net
设置 dns_domain_lo 域名
如果不使用域名的话,将 /etc/issue 中的“.\O”字符串去掉

$ nano /etc/conf.d/net
加入下列内容配置 dhcp 网络:
config_eth0=( "dhcp" )
dhcp_eth0="nodns nontp nonis"

启动时自动加载网络:
$ rc-update add net.eth0 default

设置根用户密码:
$ passwd

设置时钟:
$ nano /etc/conf.d/clock

安装必要程序:
$ emerge syslog-ng reiserfsprogs dhcpcd vim
$ rc-update add syslog-ng default

如此,系统安装宣告成功!

8. 退出系统,然后重新修改一下 gentoo.bat 和 gentoo.conf,启动新的 gentoo
9. Enjoy

PS1:也可以不用 dd,因为初始的文件都是空的(其实里面是什么内容都无所谓),所以可以写个程序调 WinAPI 直接申请个 nG 的文件了事,都不需要清空内容。不过鉴于本人能力有限,谁来写个为网民服务吧,应该很简单的(某人窃笑中……不久传来被pia声)

PS2:本人素 ReiserFS 及 Reiser4 之强烈拥护和支持者~~~~(再次被众人pia飞)

PS3:在安装完重新启动之后发现出现如下错误,无法进入系统:

putfont function not implemented

功能未实现?!上网搜索了一下,原因是 coLinux 不支持 framebuffer 所致,解决方案如下:

由于无法进入新系统,打开 host,挂上分区,运行如下指令:

$ mv /bin/setfont /bin/setfont.old
$ cat > /bin/setfont
#!/bin/bash

if ! uname -r grep -q -e "-co-" then
/bin/setfont.old $@
fi
$ chmod +x /bin/setfont

再启动即可

PS4: 没有谷歌拼音,智能abc录入累死我也~~(众人:活该~!BOM!<怎么被pia的总是我>)
PS5: binarie 看看这里什么时候会留下你的脚印。。。。。。。。

2007年5月10日星期四

愿望工作室 BLOG 开版

其实 2005 年的时候就有 Blogger 的账号,只是那个时候只能注册不能看,感到很郁闷~
现在一切都正常了,于是便重新开放这个 BLOG 作为大家交流的地方。

愿望工作室的网站空间现在也有点不正常(免费的就是鸡肋啊),所以目前所有东西就放在这个 BLOG 了。现在才发现这个东西还是很好用的,呵呵~

Operator Wiki 2.0 Test 2 现在也进入了最后的测试阶段,在不久的将来就会发布了。
这个版本加入了漏洞防御的功能,大家很快就能用到这个 Wiki 系统了,请稍事等待吧