topcoder srm 475 div1
problem1 link
暴力枚举$r$只兔子的初始位置,然后模拟即可。
problem2 link
假设刚生下来的兔子是1岁,那么能够生小兔子的兔子的年龄是至少3岁。
那么所有的兔子按照年龄可以分为1岁,2岁,大于等于3岁三种情况。不妨令个数分别为$a_{1},a_{2},a_{3}$
在每年生完兔子后,假如是四月,这时候1岁的兔子和大于等于3岁的兔子的数量是一样的($a_{1}=a_{3}$)。那么在11月的时候,如果要去掉一半的兔子,那么一定是大于等于三岁的所有兔子和2岁兔子的一半。$a_{3}=0,a_{2}=\frac{a_{2}}{2}$ or $a_{2}=\frac{a_{2}+1}{2}$
现在的问题是要确定现在2岁的兔子的个数是奇数还是偶数。不妨令三种兔子的奇偶数分别是$x_{1},x_{2},x_{3}$
假设$x_{2}=t*2^{51}+r$,$0 \leq r < 2^{51}$
那么只需要用$r$的奇偶性来代表$x_{2}$的奇偶性即可,即便有除以2,以及加1再除以2的操作。因为$t*2^{51}$除以若干次2后(小于等于50次)仍然是偶数。
problem3 link
假设有$n$只兔子
首先计算出每个兔子得分的最大值最小值。minPoints,maxPoints
设选出的selected只兔子的最后一只的编号为$x$, 假设它此时的得分 maxPoints[x]
另外假设其他选择的兔子都是它们的最高得分,而未选兔子都是它们的最低得分
令$f[i][j][k]$表示在前$i$只兔子中,有$j$只的排名高于$x$且在这$j$只中选出了$k$只的情况有多少种。那此次的答案为$Answer_{x}=\sum_{i= selected}^{qualified}f[n][i][selected]$
这里需要考虑的是,会不会出现这样的情况导致少计算了方案数:由于$x$固定得了maxPoints[x]分,而如果它的得分少于maxPoints[x]时,可能会出现某个兔子$t$的排名在$x$之前。(比如$minPoints[x]<maxPoints[t]<maxPoints[x]$)
其实这种情况不会漏算,因为当枚举$t$作为最后选出兔子的最后一只时,会算上这种情况。
因此,只需要考虑选择的兔子都是它们的最高得分,而未选兔子都是它们的最低得分即可。
code for problem1
import java.util.*; import java.math.*; import static java.lang.Math.*; public class RabbitStepping { int result = 0; String field = null; int[] q = null; int[] pre = null; public double getExpected(String field, int r) { this.field = field; q = new int[field.length()]; pre = new int[field.length()]; dfs(0, 0, r, new int[field.length()]); long p = 1; for (int i = 1; i <= r; ++ i) { p = p * (field.length() + 1 - i) / i; } return 1.0 * result / p; } void dfs(int dep, int start, int tot, int[] p) { if (dep == tot) { cal(p); return; } if (start == p.length) { return; } if (tot - dep > p.length - start) { return; } for (int i = start; i < p.length; ++ i) { p[i] = 1; dfs(dep + 1, i + 1, tot, p); p[i] = 0; } } void move(int from, int to) { q[to] += 1; q[from] -= 1; pre[to] = from; } void cal(int[] p) { for (int i = 0; i < p.length; ++ i) { q[i] = p[i]; } int size = q.length; Arrays.fill(pre, -1); int[] pre1 = new int[p.length]; int[] q1 = new int[p.length]; while (size > 2) { for (int i = 0; i < size; ++ i) { pre1[i] = pre[i]; q1[i] = q[i]; } for (int i = 0; i < size; ++ i) { if (q1[i] == 0) { continue; } if (i == 0) { move(0, 1); } else if (i == size - 1 || i == size - 2) { move(i, i - 1); } else if (field.charAt(i) == 'W'){ move(i, i - 1); } else if (field.charAt(i) == 'B') { move(i, i + 1); } else { if (size == p.length) { move(i, i - 1); } else { move(i, pre1[i]); } } } for (int i = 0; i < size; ++ i) { if (q[i] >= 2) { q[i] = 0; pre[i] = 0; } } size -= 1; } for (int i = 0; i < size; ++ i) { result += q[i]; } } }
code for problem2
import java.util.*; import java.math.*; import static java.lang.Math.*; public class RabbitIncreasing { final static int mod = 1000000009; final static long MOD = 1l << 51; final static int rev2 = Pow(2, mod - 2, mod); public int getNumber(int[] leaving, int k) { int a3 = 0, a2 = 0, a1 = 1; long x3 = 0, x2 = 0, x1 = 1; if (leaving[0] == 1) { return 0; } int t = 0; for (int i = 2; i <= k; ++ i) { a3 = (a3 + a2) % mod; a2 = a1; a1 = a3; x3 = (x3 + x2) % MOD; x2 = x1; x1 = x3; if (t < leaving.length && leaving[t] == i) { x3 = 0; a3 = 0; if ((x2 & 1) == 1) { x2 -= 1; a2 = (a2 + mod - 1) % mod; } x2 >>= 1; a2 = (int)((long)a2 * rev2 % mod); t += 1; } } return ((a3 + a2) % mod + a1) % mod; } static int Pow(int a, int b, int mod) { int result = 1; a %= mod; while (b != 0) { if ((b & 1) == 1) { result = (int)((long)result * a % mod); } a = (int)((long)a * a % mod); b >>= 1; } return result; } }
code for problem3
import java.util.*; import java.math.*; import static java.lang.Math.*; public class RabbitProgramming { int[] minPoints = null; int[] maxPoints = null; long[][][] f = null; int n; int qualified; int selected; public long getTeams(int[] points, String[] standings, int qualified, int selected) { this.n = standings.length; this.qualified = qualified; this.selected = selected; minPoints = new int[n]; maxPoints = new int[n]; for (int i = 0; i < points.length; ++ i) { for (int j = 0; j < n; ++ j) { if (standings[j].charAt(i) == 'N') { continue; } if (points[i] > 0) { minPoints[j] += points[i]; maxPoints[j] += points[i]; } else { maxPoints[j] += -points[i]; } } } f = new long[n][qualified + 1][selected + 1]; long result = 0; for (int x = 0; x < n; ++ x) { cal(x); for (int i = selected; i <= qualified; ++ i) { result += f[n - 1][i][selected]; } } return result; } void cal(int x) { for (int i = 0; i < n; ++ i) { for (int j = 0; j <= qualified; ++ j) { Arrays.fill(f[i][j], 0); } } if (x == 0) { f[0][1][1] = 1; } else { if (minPoints[0] < maxPoints[x]) { f[0][0][0] = 1; } else { f[0][1][0] = 1; } if (maxPoints[0] >= maxPoints[x]) { f[0][1][1] = 1; } } for (int i = 1; i < n; ++ i) { for (int j = 0; j <= qualified; ++ j) { for (int k = 0; k <= selected; ++ k) { final long val = f[i - 1][j][k]; if(val == 0) { continue; } if (i == x) { if (j < qualified && k < selected) { f[i][j + 1][k + 1] += val; } continue; } if (i < x && minPoints[i] < maxPoints[x] || i > x && minPoints[i] <= maxPoints[x]) { f[i][j][k] += val; } else if(j < qualified) { f[i][j + 1][k] += val; } if ((i < x && maxPoints[i] >= maxPoints[x] || i > x && maxPoints[i] > maxPoints[x]) && j < qualified && k <selected) { f[i][j + 1][k + 1] += val; } } } } } }