zbwmqlw

Single Round Match 504

比赛临近结束的时候TC服务器似乎出了点状况, 交不上题, 于是本场就没有记rating. 250和500偏易, 1000是一个计数问题, 赛后研究题解发现其实也不是非常难想...但是还是不可能凭借自己的脑子想出来...

250pt MathContest

一个栈, 里面装着球, 有黑球和白球两种类型. 不断从栈中拿出球, 如果拿出的是白球, 那就把栈头尾翻转, 如果拿出的是黑球, 那么就把所有球的颜色翻转(白变黑, 黑变白). 问最终拿出了多少个黑球.

设置两个bool标记分别表示栈的顺序是否翻转以及球的颜色是否翻转, 直接模拟就行了.

500pt AlgridTwo

对于H行W列的黑白矩阵, 对其进行变换的伪代码为:

For i = 0 to H-2:
    For j = 0 to W-2:
        //Get the current colors of cells (i,j) and (i,j+1)
        A = Color(i,j) , B = Color(i,j+1)

        If (A,B) == (White, White) Then:
             Do nothing.
        EndIf
        If (A,B) == (Black, White) Then: 
             Repaint cells (i+1,j) and (i+1,j+1) Black.
        EndIf
        If (A,B) == (White, Black) Then:
             Repaint cells (i+1,j) and (i+1,j+1) White.
        EndIf
        if (A,B) == (Black, Black) Then:
             Swap the colors in cells (i+1,j) and (i+1,j+1).
        EndIf
    EndFor
EndFor

给定变换后的矩阵, 求有多少个初始矩阵能得到这个变换后的矩阵.

变换后矩阵的第i行只会影响到变换前矩阵的第i + 1行, 所以不同行之间是不会相互干扰的, 于是我们可以对于每一行单独计数, 乘起来作为答案.

当对第i行进行操作时, 会把第i + 1的某些元素变为黑色或白色, 这些元素的初始颜色就被覆盖掉了, 所以这些元素初始时无论是黑色或白色都是无所谓的. 而对于其他没有被染色的元素, 只需要与变换后矩阵的相应元素的颜色保持一致就可以了.

于是我们可以一行一行处理, 模拟染色过程, 模拟完成后校对染色后的矩阵是否与题目给定的矩阵相符, 若相符则返回2 ^ (被染色的元素个数), 否则返回0.

1000pt Stackol

对于一个由'A', 'B'和'C'组成的字符串program, 程序的伪代码如下:

For i = 0 to length(program)-1 :
    If (i==0) or (program[i-1]!='B') then
        push program[i] to the top of stack1.
    Else
        push program[i] to the top of stack2.
    EndIf
    If (program[i]=='C') then 
        printAndEmptyStack(stack1)
        printAndEmptyStack(stack2)
    EndIf
EndFor

其中printAndEmptyStack过程的伪代码为:

While (stack is not empty):
    If (top character in stack) is 'A' or 'B' then
        Print (top character in stack)
    EndIf
    Remove the top character from the stack.
EndWhile

给定程序的输出output(由'A'和'B'组成的字符串), 求有多少个输入字符串能够得到给定输出. 输入字符串中的'C'的个数不大于K, 且以'K'结尾.

首先发现'C'的作用就是把字符串分割成了几部分仅由'A'和'B'组成的子字符串, 每部分之间相互不影响, 无后效性, 可提出如下动态规划方案:

令dp[i][k]表示使用k个字符'C', 得到output.substr(i)的方案数, dp[i][k] = sigma(dp[j][k - 1] * ways[i][j], i <= j <= n), 其中ways[i][j]表示不使用字符'C', 得到字符串output.substr(i, j - i)的方案数. 这样时间复杂度为O(n ^ 2 * K), 在TopCoder的强力评测机的帮助下, 可以通过本题.

下面考虑如何计算ways[i][j].

output.substr(i, j - i)是由两部分组成的, 其中output.substr(i, k)由stack1得到, output.substr(i + k, j - i - k)由stack2得到. 枚举k后, 由结果字符串逆推回去就可以得到初始字符串, 所以ways[i][j]等于k的合法取值数. 由于初始字符串中每个字符的归属由其前一个字符决定('A'则进入stack1, 'B'则进入stack2), 因此stack1中元素的数量一定为[output.substr(i, j - i)中'A'的数量 + (0或1)], 故ways[i][j]取值只能为0, 1或2, 所以可以枚举k, 判断是否合法.

stack1中的'B'会把当前指针移动到stack2, stack2中的'A'会把当前指针移动到stack1, 初始时指针是在stack1内的. 令lB表示stack1中'B'的数量, rA表示stack2中'A'的数量, 那么只能有lB = rA或lB = rA + 1. 当lB = rA时, 指针最终会落在stack1内, 所以此时stack2栈底的元素必须为'A'(否则stack2栈底的元素将没有机会出栈). 同样, 当lB = rA + 1时, 指针最终会落在stack2内, 此时stack1栈底的元素必须为'B'.

所以当预处理ways[i][j]时, 只需要枚举两种可能的k值, 并O(1)判定是否合法. 总时间复杂度预处理O(n ^ 2) + 动态规划O(n ^ 2 * K).

posted on 2011-04-30 14:15  zbwmqlw  阅读(404)  评论(1)    收藏  举报