TopCoder SRM296 DIV1 Report
match date:Monday, April 3, 2006
report date:Monday, April 10, 2006
该好好反省了,在DIV1始终还是不能有好的表现。这次靠几个数据Challenge了几个代码,但题目还是没能做出来,看来水平还是不济啊。
貌似简单的一道题,可以用动规快速解决,但我当时只是觉得简单,采用了直接算的方法,没想到这题肮脏的数据这么多。
从i=1开始处理到nSongs张歌曲,每个i的最佳摆法是:
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数组是可以解决的。下式的mem是DP数组,t表示第t次变化,c表示从c字母开始变,i表示变成i字母。而move[i][j] 表示 i字母转变一次后第j位的字母。
mem[t][c][i] = sum ( mem[t-1][ move[c][k] ][i] ) k=1..3
然后考虑如何取从left到right的位置之间的字母个数,由于任意字母转变n次后的字母个数是3^n,所以只要计算3^n与left和right的关系就可以了,同时要注意3^n可能会超出整数范围:
long[] solve( int c, int t, long left, long right) { // 递归求left与right之间的解
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) { // left和right的范围很大
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) ; //旋转函数,p是rotate中一个值,返回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();
}
}
}
}
下一个要考虑的问题是着色问题,一样用暴力的方法来解决。用7层for语句对一个brick枚举所有的着色,然后计算该着色对于所有输入的颜色差,取一个最小值就是结果了。计算一种着色与一个输入的颜色差需要考虑到24种旋转。
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