TopCoder College Tour - WestChina

【2008.06.08】
【TopCoder College Tour - WestChina】

Summary : 今天的题目其实很简单,可惜仍然是速度不够,最后一题想出算法来却来不及编写。看来想要在Div1混下去还是得提高coding熟练度。今天状态实在不好,500分那题没考虑清楚,后来Challenge的时候真想自己把自己给Cha了赚50分=。=    总的来说现在做250分的那道题基本上可以拿到220左右的分数了,现阶段目标是提高速度,争取能在500分的题目上拿400+的分数!

Problems:

250分题
【Problem Statement】
给出一个8x8棋盘
#.#.#.#.
.#.#.#.#
#.#.#.#.
.#.#.#.#
#.#.#.#.
.#.#.#.#
#.#.#.#.
.#.#.#.# 
其中"B","W",".","#"分别代表黑棋,白棋,白格子,黑格子。行编号从1到8,列编号从A到H。题目给出棋子的位置,输出摆上棋子之后的棋盘样子。

【Solution】
250分的题目通常是用来热身的,直接模拟就行,代码能写多短就写多短。通常看看高手的程序能学到很多技巧,高手的程序那叫一个赏心悦目啊——简约而不简单!今天在250分的题目上我也简短了一把= v =


500分题
【Problem Statement】
有一个机器人,只会按照长度为N的指令序列进行移动,每次移动的指令为"U"(x,y)->(x,y+1)或者"R"(x,y)->(x+1,y),给出机器人初始坐标(RobotX,RobotY)和陷阱目标(TrapX, TrapY),求能让机器人走入陷阱的指令序列。(指令循环执行)若不存在这样的序列则输出"I'LL GET YOU NEXT TIME",若有多种答案则输出字符串比较最小的方案。

【Solution】
       这道题麻烦就麻烦在特殊情况,像(RobotX,RobotY) == (TrapX,TrapY),RobotX==TrapX,RobotY==TrapY,这种特殊情况还算好处理的,在计算模的时候对于边界的处理总会让人很晕。于是这时候最好能找到一个能覆盖到所有特殊情况的写法,使得我们不需要去一一处理每个特殊情况。
       解这道题的突破口在于循环次数上,如果我们知道这个N长度的指令循环将执行多少次,那么我们可以通过枚举指令序列中的U和R的个数来构造指令串。想到这一点问题就好办了,因为每次不管机器人向上还是向右,他总需要移动1的距离,我们只需要算出机器人与陷阱之间的街区距离(TrapX-RobotX)+(TrapY-RobotY)即可知道机器人要走进陷阱所需要的确切步数totstep,然后用circles = totstep / n求得整轮数,令rx,和ry表示机器人走了circle轮之后还需走多少步掉入陷阱,则rx = (TrapX - RobotX) - circles * nR; ry = (TrapY - RobotY) - circles *nU;此时我们只需要枚举nU(即N-nR)即可获得每种情况下的rx,ry,然后将rx个R放在最前面,接下来ry个U,再把剩下的R和U按顺序填上去,即可构成我们需要的串。最后在这些串里头找个最小的返回即可。

1000分题
【Problem Statement】
      我们现在有N个能按照顺序显示字符串中字母('A'-'Z',且每个字符串中没有相同字符,字符串最大长度为26)的屏幕,若第i秒某个屏幕显示的为第k个字母,则i+1秒显示的为第k+1个字母(遇到末尾返回到首个)。在第0秒所有的屏幕显示的均为每个字符串的第一个字母,现在给出这些字符串以及希望看到的单词,问最少多少秒后能看到希望看到的单词,无解则输出-1。

Example:
{"XYZ", "DEF", "OPRS"}
"YES"
Returns: 7
The message displayed at each second is:
0: XDO
1: YEP
2: ZFR
3: XDS
4: YEO
5: ZFP
6: XDR
7: YES

【Solution】
      设第i个字符串的长度为len(i),编号从0开始。
      我最开始的想法是先找到第0个屏幕出现所需字母的时间k,然后每次增加incr = len(0)依次检查其他未出现要求字母的屏幕,若j号屏幕在k+len(0)出现的为所求的字符,则接下来每次增量incr改成incr和len(j)的最小公倍数,依次类推,直到所有的屏幕均满足条件或超出所有字符串长度最小公倍数为止。但是这样每次都扫描一遍所有的字符串太麻烦,后来发现可以改成按照顺序求,即:从0~N-1,每一步(i)都求出第0到第i个屏幕上的显示均符合要求的最小时刻,每找到一个,则更新incr为前i+1个字符串长度的最小公倍数。由于这个最小公倍数增长得十分快,所以很快就会找到答案或者超出所有字符串长度的最小公倍数,因此时间效率并不是问题。不过在测试的时候我还是有个小地方出了问题:在该用long long的时候只用了int,结果导致输出了负数,实在是不应该。

看到某大牛写的相当简练的求最大公约数代码:


【The End】

vector <string> TextBoard::draw(vector <string> pieces) {
        vector<string> vs(8, "########");
        for (int i=0; i<8; ++i)
                for (int j=0; j<8; ++j)
                        vs[i][j] =  (i+j)%2 ? '.' : '#';
        for (int i=0; i<pieces.size(); ++i) {
                int x = pieces[i][7] - '1';
                int y = pieces[i][6] - 'A';
                vs[x][y] = pieces[i][0];
        }
        return vs;
}

 

string EvilRobot::createProgram(int N, int robotX, int robotY, int trapX, int trapY) {
        int dx = trapX - robotX;
        int dy = trapY - robotY;
        int     tot = dx + dy;
        int t  = tot / N;
        if (dx<0 || dy<0) return "I'LL GET YOU NEXT TIME";
        string ans;
        for (int nU = 0; nU<=N; ++nU) {
                int nR = N - nU;
                int rx = dx - nR * t;
                int ry = dy - nU * t;
                //printf("nU=%d, nR=%d, rx=%d, ry=%d/n", nU, nR, rx, ry);
                if (rx < 0 || ry < 0 || rx > nR || ry > nU) continue;
                string s;
                for (int i=0; i<rx; ++i) s+='R';
                for (int i=0; i<ry; ++i) s+='U';
                for (int i=0; i<nR-rx; ++i) s+='R';
                for (int i=0; i<nU-ry; ++i) s+='U';
                //printf("s=%s ans=%s/n", s.c_str(), ans.c_str());
                if (ans == "" || s<ans) ans = s;
        }
        return ans == "" ? "I'LL GET YOU NEXT TIME" : ans;
};

 

long long RollingLetters::gcd(long long a, long long b) {
        return (b ? gcd(b, a%b) : a);
}
long long RollingLetters::getTime(vector <string> reels, string requiredText) {
        long long ans = 0;
        long long mod = 1;
        for (int i=0; i<reels.size(); ++i) {
                int j;
                for (j=0; j<reels[i].length(); ++j) {
                        if (reels[i][j] == requiredText[i]) break;
                }
                long long cntm = reels[i].length();
                int suc = false;
                for (long long k = mod; k < (1ULL<<63) && k / mod <= cntm; k += mod) {
                        if ((ans + (k-mod)) % cntm == j) {
                                suc = true;
                                ans += (k-mod);
                                mod *= cntm / gcd(mod, cntm);
                                break;
                        }
                }
                if (!suc) return -1;
        }
        return ans;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值