TopCoder SRM296 DIV1 Report

TopCoder SRM296 DIV1 Report


match dateMonday, April 3, 2006

report dateMonday, April 10, 2006


Preface:

该好好反省了,在DIV1始终还是不能有好的表现。这次靠几个数据Challenge了几个代码,但题目还是没能做出来,看来水平还是不济啊。


Problem 250 - NewAlbum :

貌似简单的一道题,可以用动规快速解决,但我当时只是觉得简单,采用了直接算的方法,没想到这题肮脏的数据这么多。


i=1开始处理到nSongs张歌曲,每个i的最佳摆法是:


  1. best[i] = min( best[i] , best[i-j]+1 ) j=1..min(i,cdCapacity)


其中j表示在best[i-j]CD后,把j放在另一张CD内。当然必须保证j不能被13整除。

直接算也是有人过的,不过要考虑一些特殊的情况。包括如果剩下13张等待处理,而之前的CD都摆了15张时,可以从前面移一张过来,而如果前面的CD是摆放了14张的话则不行。


Problem 500 - StringReplacements:

第二题目用到了两次递规,看过解题报告后才知道,原来递归的思想是如此神奇,真该培养一下递归的能力了。

首先,先考虑如何计算由单个字母变化n次后的各字母数量。用一个DP数组是可以解决的。下式的memDP数组,t表示第t次变化,c表示从c字母开始变,i表示变成i字母。而move[i][j] 表示 i字母转变一次后第j位的字母。

  1. mem[t][c][i] = sum ( mem[t-1][ move[c][k] ][i] ) k=1..3

然后考虑如何取从leftright的位置之间的字母个数,由于任意字母转变n次后的字母个数是3^n,所以只要计算3^nleftright的关系就可以了,同时要注意3^n可能会超出整数范围:


long[] solve( int c, int t, long left, long right) { // 递归求leftright之间的解

    long[] res = new long[3]; // 存放解

    long max = (long) Math.pow(3, t); // 3^t 指最大范围

    if (left == right && left == 0 && t == 0) { // 特别处理一下只有一个字母

        res[c]++; // 且不需要变换的情况

    } else if (left <= 0 && right >= max) { // leftright的范围很大

        return getGen(c, t); // 可以直接返回前面求的men

    } else if (left <= right) {


            int del = (int) Math.pow(3, t – 1); // 3^(t-1),指转变后三个之 // 间的间隔

            for (int i = 0; i < 3; i++) { // 循环求三个子字母的解

                left = left < 0 ? 0 : left; // left保证大于等于0

                right = right > max ? max : right; // right保证小于等于最大可能

                long[] add = solve(move[c][i], t - 1, left, right); // 递归求一个字母解

                for (int j = 0; j < 3; j++) {

                    res[j] += add[j]; // 累加解

                }

                left -= del; //left 变为下一个字母的left

                right -= del; //变为下一个字母的right

            }

        }

       return res;

}


Problem 1000 - ColoredBricks :

这题比较烦琐,考验编程速度和量的。首先求出所有的翻转,共计24种,一个面可以有六个位置的可能性,这个面相邻的面可以看出,通过一个旋转,是有四种可能。因为只要固定了一个面和与它相邻的那个面色子就固定了,所以6个可能乘4个可能就是24种情况。


// 301245 是从正面向上面旋转

// 052413 是从左边向上面旋转

// 514302 是从左边向正面旋转

int[][] rotate = { { 3, 0, 1, 2, 4, 5 }, { 0, 5, 2, 4, 1, 3 },

{ 5, 1, 4, 3, 0, 2 } };


int[] rot(int[] x, int[] p) ; //旋转函数,protate中一个值,返回x转后值


void generateRotate() { //生成24种可能

    int i, j, k, l = 0;

    int[] x = new int[] { 0, 1, 2, 3, 4, 5 };

    r = new int[24][6];


    for (i = 0; i < 4; i++) {

        x = rot(x, rotate[0]);

        for (j = 0; j < 4; j++) {

            x = rot(x, rotate[1]);

            NEXT: for (k = 0; k < 4; k++) {

                x = rot(x, rotate[2]);

                    for (int[] e : r) {

                        if (Arrays.equals(e, x))

                            continue NEXT;

                    }

                r[l++] = x.clone();

                }

            }

        }

}


下一个要考虑的问题是着色问题,一样用暴力的方法来解决。用7for语句对一个brick枚举所有的着色,然后计算该着色对于所有输入的颜色差,取一个最小值就是结果了。计算一种着色与一个输入的颜色差需要考虑到24种旋转。


Links:

My Blog:

http://blog.csdn.net/ray58750034/


My statistic:

http://www.topcoder.com/stat?c=coder_room_stats&rd=9817&cr=20862220


SRM 289 - Problem Set & Analysis:

http://www.topcoder.com/tc?module=Static&d1=match_editorials&d2=srm296


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值