topcoder srm 465 div1
problem1 link
以两个点$p,q$为中心的两个正方形的边长和最大为$2dist(p,q)$,即$p,q$距离的两倍。
也就是两个$p,q$的连线垂直穿过两个正方形的一对边且平分两个正方形。
problem2 link
简化一下题意就是每个base和每个plant都有一个代价。要么付出某个base的代价,要么付出其对应的plant的代价。
将base和plant建立网络流。
源点到每个plant的边的流量为其代价
base到汇点的边的流量为其代价
base与其对应plant的边的流量为无穷大。
然后求最小割即可。
割到的plant就说明要付出这个plant的代价,割到的base就说明付出这个base的代价。
problem3 link
令$p=\frac{1}{d},q=\frac{d-1}{d}$
在$[n-d,n-1]$中任意一个格子,其一步到达$n$的概率都是$p$。恰好经过$t$步到达$n$的概率为$pq^{t-1}$
设$p1[i]$表示先手恰好经过$i$步第一次进入$[n-d,n-1]$区间的概率;
设$p2[i]$表示后手恰好经过$i$步第一次进入$[n-d,n-1]$区间的概率;
设$g(i,j)$表示先手、后手分别经过$i,j$步到达$[n-d,n-1]$区间且先手胜利的概率。
$g(i,j)$的计算方法为:
===============================
g(i,j)=0
if(i<j) {
$g(i,j) += p1[i]*p2[j]*(1-q^{j-i})$ //在后手未进入最后区间时取得胜利
}
$g(i,j)+=p1[i]*p2[j] * q^{|i-j|} * \frac{d}{d+d-1}$ //都进入最后区间再经过若干轮角逐后取得胜利
===============================
那么答案为所有的$g(i,j)$之和。
code for problem1
import java.util.*; import java.math.*; import static java.lang.Math.*; public class TurretPlacement { public long count(int[] x, int[] y) { long result = 0; for (int i = 0; i < x.length; ++ i) { for (int j = i + 1; j < x.length; ++ j) { result += cal(x[i], y[i], x[j], y[j]); } } return result; } long cal(int x1, int y1, int x2, int y2) { long d = (long)(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) * 2); return d * (d - 1) / 2; } }
code for problem2
import java.util.*; import java.math.*; import static java.lang.Math.*; class MaxFlow { static class node { int v,cap,next; }; List<node> edges = null; int[] head = null; int vertexNum; int[] pre = null; int[] cur = null; int[] num = null; int[] h = null; public MaxFlow(int vertexNum) { this.vertexNum = vertexNum; edges = new ArrayList<>(); head = new int[vertexNum]; Arrays.fill(head, -1); pre = new int[vertexNum]; cur = new int[vertexNum]; num = new int[vertexNum]; h = new int[vertexNum]; } private void addEdge(int u, int v, int cap) { node p = new node(); p.v = v; p.cap = cap; p.next = head[u]; head[u] = edges.size(); edges.add(p); } public void add(int u, int v, int cap) { addEdge(u, v, cap); addEdge(v, u,0); } public int getMaxflow(int source, int sink) { for (int i = 0; i < vertexNum; ++ i) { cur[i] = head[i]; num[i] = 0; h[i] = 0; } int u = source; int result = 0; while (h[u] < vertexNum) { if (u == sink) { int Min=Integer.MAX_VALUE; int v = -1; for (int i = source; i != sink; i = edges.get(cur[i]).v) { int k=cur[i]; if(edges.get(k).cap < Min) { Min = edges.get(k).cap; v = i; } } result += Min; u=v; for (int i = source; i != sink; i = edges.get(cur[i]).v) { int k=cur[i]; edges.get(k).cap -= Min; edges.get(k ^ 1).cap += Min; } } int index = -1; for (int i = cur[u]; i != -1; i = edges.get(i).next) { if (edges.get(i).cap > 0 && h[u] == h[edges.get(i).v] + 1) { index = i; break; } } if (index != -1) { cur[u] = index; pre[edges.get(index).v]=u; u=edges.get(index).v; } else { if (--num[h[u]] == 0) { break; } int k = vertexNum; cur[u] = head[u]; for (int i = head[u]; i != -1; i = edges.get(i).next) { if(edges.get(i).cap>0 && h[edges.get(i).v] < k) { k = h[edges.get(i).v]; } } if (k + 1 < vertexNum) { num[k + 1] += 1; } h[u] = k + 1; if (u != source) u=pre[u]; } } return result; } } public class GreenWarfare { int p2(int x) { return x * x; } public int minimumEnergyCost(int[] canonX, int[] canonY, int[] baseX, int[] baseY, int[] plantX, int[] plantY, int energySupplyRadius) { final int n = baseX.length; final int m = plantX.length; MaxFlow maxFlow = new MaxFlow(n + m + 2); for (int j = 0; j < m; ++ j) { int c = Integer.MAX_VALUE; for (int i = 0; i < canonX.length; ++ i) { c = Math.min(c, p2(canonX[i] - plantX[j]) + p2(canonY[i] - plantY[j])); } maxFlow.add(0, j + 1, c); } for (int j = 0; j < n; ++ j) { int c = Integer.MAX_VALUE; for (int i = 0; i < canonX.length; ++ i) { c = Math.min(c, p2(canonX[i] - baseX[j]) + p2(canonY[i] - baseY[j])); } maxFlow.add(m + j + 1, m + n + 1, c); } for (int i = 0; i < m; ++ i) { for (int j = 0; j < n; ++ j) { int d = p2(baseX[j] - plantX[i]) + p2(baseY[j] - plantY[i]); if ( d <= p2(energySupplyRadius)) { maxFlow.add(i + 1, m + j + 1, Integer.MAX_VALUE); } } } return maxFlow.getMaxflow(0, m + n + 1); } }
code for problem3
import java.util.*; import java.math.*; import static java.lang.Math.*; public class BouncingDiceGame { public double winProbability(int n, int d, int x, int y) { double[] p1 = cal(n, d, x); double[] p2 = cal(n, d, y); double[] p = new double[n]; p[0] = 1; p[1] = (d - 1.0) / d; for (int i = 2; i < n; ++ i) { p[i] = p[i - 1] * p[1]; } double result = 0; for (int i = 0; i < p1.length; ++ i) { for (int j = 0; j < p2.length; ++ j) { if (i < j) { result += p1[i] * p2[j] * (1 - p[j - i]); } result += p1[i] * p2[j] * p[Math.abs(i - j)] * d / (d + d - 1); } } return result; } double[] cal(int n, int d, int x) { if (x >= n - d) { double[] result = new double[1]; result[0] = 1; return result; } final int m = n - d - x; double[] result = new double[m + 1]; result[0] = 0; double[][] f = new double[2][n]; for (int i = x; i <n; ++ i) { f[0][i] = 1; } int pre = 0; int cur = 1; for (int i = 1; i <= m; ++ i) { Arrays.fill(f[cur], 0); for (int j = x + 1; j < n; ++ j) { int rr = j - 1 >= n - d? n - d - 1 : j - 1; int ll = j - d - 1 >= 0? j - d - 1: 0; if (rr < ll) { continue; } f[cur][j] = (f[pre][rr] - f[pre][ll] ) / d; } for (int j = x; j < n; ++ j) { f[cur][j] += f[cur][j - 1]; } result[i] = f[cur][n - 1] - f[cur][n - d - 1]; pre ^= 1; cur ^= 1; } return result; } }