topcoder srm 485 div1
problem1 link
枚举第一个数和第二个数即可确定公差。
problem2 link
设高度为$n$,宽度为$m$,且$n \ge m$
如果$m \ge 5$,那么答案为0。这个可以通过抽屉原理来说明。考虑第一行,假设$n=m=5$,那么第一行最后一定有至少3个白色或黑色,不妨设为白色。不妨单独将这3列抽出来,现在就是一个$5*3(n=5)$的矩阵。那么对于第2,3,4,5行来说,不会存在一行有两个白色。对于黑色格子来说有两种情况:
(1)存在一行有三个黑色。那么其他三行不能有两个或者三个黑色,所以只能是一个黑色,这意味有两个白色,这样就和第一行冲突了。
(2)不存在任意一行有三个黑色,因为也不能有两个白色,所以只能是一个白色两个黑色,那么有三种排列方式,黑黑白,黑白黑,白黑黑。这样的话只能满足4行,第五行无论怎么放置都会冲突。如下图所示:
所以只需要考虑$m \le 4$的情况。
假设$m=4$,假设已经放置好了第1行到第$i-1$行,那么对于第$i$行来说,只需要记录一些信息来判断第$i$行的某两列是否可以都是白色或者都是黑色即可(保证不跟上面的某一行的两列形成不合法的情况)。
这样的话只有$C_{4}^{2}=6$种情况,即:0011,0101,1001,0110,1010,1100。将它们编号为0到5.
设dp的数组为$f[n][2^{6}][2^{6}]$
所以可以用一个状态$f[i][wst][bst]$来表示前$i$行放置之后,后面每一行不能出现白色格子的状态为$wst$且黑色格子状态为$bst$的放置方案数。
problem3 link
首先,对于凸包H上任意一点p,H上距离p最远的点一定是H的某个顶点。
其次,距离凸包上p附近的一些点的最远顶点必定跟距离p的最远顶点是同一个顶点。
所以,首先需要对H的边进行一些划分,也就是划分成若干个片段,每个片段的最远点是同一个顶点。划分的方法是枚举H的任意两个顶点$a,b$,线段$ab$的垂直平分线将H分为两半,一半的点到$a$的距离最大,另一半到$b$最大。该垂直平分线与H有两个交点。将所有的这样的交点收集在一起,那么任意两个相邻的交点所划分的一定是满足上面描述的一个片段。
然后就是对每个片段依次进行计算。设片段为$s$,距离$s$的最远点为$L$,其实就是计算假设$L$有一个光源,$s$上有多长的距离被内部凸包遮挡。可以这样计算:枚举内部凸包的每个点$p$,计算由$p,L$确定的直线与线段$s$的交点,那么对于任意两个$s$上的相邻交点$p_{1},p_{2}$,如果$p_{1},p_{2}$的中点与$L$组成的线段与内部凸包有交点,那么线段$p_{1}p_{2}$被遮挡。
code for problem1
import java.util.*; import java.math.*; import static java.lang.Math.*; public class AfraidOfEven { final static int MAX = Integer.MAX_VALUE; public int[] restoreProgression(int[] seq) { final int n = seq.length; int[] result = new int[n]; for (long a = 1; a * seq[0] <= MAX; a <<= 1) { for (long b = 1; b * seq[1] <= MAX; b <<= 1) { result[0] = (int)(seq[0] * a); result[1] = (int)(seq[1] * b); if (check(result, seq)) { return result; } } } return result; } boolean check(int[] a, int[] b) { int d = a[1] - a[0]; for (int i = 2; i < b.length; ++ i) { long t = b[i]; while (t <= MAX && t - a[i - 1] != d) { t <<= 1; } if (t > MAX) { return false; } a[i] = (int)t; } return true; } }
code for problem2
import java.util.*; import java.math.*; import static java.lang.Math.*; public class RectangleAvoidingColoring { public long count(String[] board) { if (board.length >= 5 && board[0].length() >= 5) { return 0; } if (board[0].length() >= 5) { String[] board1 = new String[board[0].length()]; for (int i = 0; i < board[0].length(); ++ i) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < board.length; ++ j) { sb.append(board[j].charAt(i)); } board1[i] = sb.toString(); } return count(board1); } final int n = board.length; final int m = board[0].length(); if (m == 1) { long result = 1; for (int i = 0; i < n; ++ i) { if (board[i].charAt(0) == '?') { result <<= 1; } } return result; } final int K = m * (m - 1) / 2; int[] T1 = new int[1 << m]; for (int i = 0, id = 0; i < (1 << m); ++ i) { int num = 0; for (int j = 0; j < m; ++ j) { if (contains(i, 1 << j)) { ++ num; } } if (num == 2) { T1[i] = id ++; } } int[][] T = new int[1 << m][2]; for (int i = 0; i < (1 << m); ++ i) { int b = 0; int w = 0; for (int x = 0; x < m; ++ x) { boolean bx = contains(i, 1 << x); for (int y = x + 1; y < m; ++ y) { boolean by = contains(i, 1 << y); if (bx != by) { continue; } if (by) { b |= 1 << T1[1 << x | 1 << y]; } else { w |= 1 << T1[1 << x | 1 << y]; } } } T[i][0] = w; T[i][1] = b; } long[][][] f = new long[n + 1][1 << K][1 << K]; f[0][0][0] = 1; for (int i = 1; i <= n; ++ i) { for (int wst = 0; wst < (1 << K); ++ wst) { for (int bst = 0; bst < (1 << K); ++ bst) { final long val = f[i - 1][wst][bst]; if (val == 0) { continue; } for (int st = 0; st < (1 << m); ++ st) { if (check(st, board[i - 1])) { int w = T[st][0]; int b = T[st][1]; if (contains(wst, w) || contains(bst, b)) { continue; } f[i][wst | w][bst | b] += val; } } } } } long result = 0; for (int wst = 0; wst < (1 << K); ++ wst) { for (int bst = 0; bst < (1 << K); ++bst) { result += f[n][wst][bst]; } } return result; } static boolean contains(int st, int sub) { return (st & sub) != 0; } static boolean check(int st, String s) { for (int i = 0; i < s.length(); ++ i) { int t = (st >> i) & 1; if (t == 0 && s.charAt(i) == 'B' || t == 1 && s.charAt(i) == 'W') { return false; } } return true; } }
code for problem3
import java.util.*; public class Deposit { static final double EPS = 1e-9; static boolean isZero(double x) { return -EPS < x && x < EPS; } static class Point { double x; double y; Point() {} Point(double x, double y) { this.x = x; this.y = y; } double multiply(Point p) { return x * p.y - y * p.x; } Point multiply(double t) { return new Point(x * t, y * t); } Point divide(double t) { return new Point(x / t, y / t); } Point substract(Point p) { return new Point(x - p.x, y - p.y); } Point add(Point p) { return new Point(x + p.x, y + p.y); } Point vertical() { return new Point(-y, x); } double length() { return Math.sqrt(x * x + y * y); } boolean equals(Point p) { return isZero(x - p.x) && isZero(y - p.y); } } static class PointComparator implements Comparator<Point> { Point start; PointComparator(Point start) { this.start = start; } public int compare(Point o1, Point o2) { double d1 = o1.substract(start).length(); double d2 = o2.substract(start).length(); if (isZero(d1 - d2)) { return 0; } return d1 < d2? -1 : 1; } } Point[] out = null; Point[] inner = null; int n; int m; public double successProbability(int[] siteX, int[] siteY, int[] depositX, int[] depositY) { n = siteX.length; out = new Point[n]; for (int i = 0; i < n; ++ i) { out[i] = new Point(siteX[i], siteY[i]); } m = depositX.length; inner= new Point[m]; for (int i = 0; i < m; ++ i) { inner[i] = new Point(depositX[i], depositY[i]); } double sum = 0; for (int i = 0; i < n; ++ i) { sum += out[i].substract(out[(i + 1) % n]).length(); } double validLength = 0; for (int i = 0; i < n; ++ i) { Point p = out[i]; Point q = out[(i + 1) % n]; validLength += calculate(p, q); } return validLength / sum; } double calculate(Point start, Point end) { List<Point> allRange = new ArrayList<>(); allRange.add(start); allRange.add(end); for (int i = 0; i < n; ++ i) { for (int j = i + 1; j < n; ++ j) { Point p = out[i].add(out[j]).multiply(0.5); Point q = p.add(out[i].substract(out[j]).vertical()); if (isParallel(start, end, p, q)) { continue; } Point c = getLineCrossLine(start, end, p, q); if (isOnSegment(c, start, end)) { allRange.add(c); } } } Collections.sort(allRange, new PointComparator(start)); double result = 0; for (int i = 0; i + 1 < allRange.size(); ++ i) { Point a = allRange.get(i); Point b = allRange.get(i + 1); if (a.equals(b)) { continue; } Point f = getFarthestPoint(a.add(b).multiply(0.5), out); result += checkBlocked(a, b, f, inner); } return result; } static boolean isBetween(double a, double L, double R) { if (L < R) { return L - EPS < a && a < R + EPS; } return R - EPS < a && a < L + EPS; } static boolean isOnSegment(Point a, Point p, Point q) { return isBetween(a.x, p.x, q.x) && isBetween(a.y, p.y, q.y); } double checkBlocked(Point start, Point end, Point L, Point[] h) { List<Point> list = new ArrayList<>(); list.add(start); list.add(end); for (Point hp: h) { if (isParallel(start, end, L, hp)) { continue; } Point p = getLineCrossLine(start, end, L, hp); if (isOnSegment(p, start, end)) { list.add(p); } } Collections.sort(list, new PointComparator(start)); double result = 0; for (int i = 0; i + 1 < list.size(); ++ i) { Point p = list.get(i); Point q = list.get(i + 1); if (p.equals(q)) { continue; } if (isIntersectConvex(p.add(q).multiply(0.5), L, h)) { result += p.substract(q).length(); } } return result; } static boolean isIntersectConvex(Point p, Point q, Point[] h) { for (int i = 0; i < h.length; ++ i) { Point a = h[i]; Point b = h[(i + 1) % h.length]; if (isParallel(a, b, p, q)) { continue; } Point c = getLineCrossLine(a, b, p, q); if (isOnSegment(c, p, q) && isOnSegment(c, a, b)) { return true; } } return false; } static boolean isParallel(Point a, Point b, Point p, Point q) { return isZero(a.substract(b).multiply(p.substract(q))); } static Point getFarthestPoint(Point p, Point[] h) { int id = 0; double dmax = 0; for (int i = 0; i < h.length; ++ i) { Point q = h[i]; double d = p.substract(q).length(); if (d > dmax) { id = i; dmax = d; } } return h[id]; } static Point getLineCrossLine(Point a, Point b, Point p, Point q) { double s1 = p.substract(a).multiply(q.substract(a)); double s2 = q.substract(b).multiply(p.substract(b)); return a.multiply(s2).add(b.multiply(s1)).divide(s1 + s2); } }