topcoder srm 460 div1

problem1 link

设$f[i][j]$表示已经分配了answers中的前$i$个,分配给的问题的状态为 $j$的方案数。

其中状态可以用$n$位的三进制表示,0表示还未分配,1表示已分配是 Yes,2表示已分配是No.

problem2 link

假设$n$个城市为[0,n-1]。设$f[i][j][t]$表示在[0,i]个城市中已经选择了$j$个城市,选择了$t$个人的概率。

那么选择第$i+1$个城市的概率是$\frac{k-j}{n-i-1}$.

problem3 link

首先,如果一个连通图中存在两个环,也就是有$n$个顶点,$n+1$条边,那么从其中一个环上的某一点(这一点不属于另外一个环)到另一个环上的某一点(同样这一点也不属于前一个环)会有超过两条简单路径。所以满足条件的连通图要么是树,要么是只有一个环(也就是树上多一条边)。

假设给出的边使得$n$个顶点分成了$m$个连通分量,第$i$个连通分量中点的个数是$v_{i}$。

(1)假设最后是一棵树(前提是$m$个连通分量中每个连通分量中都没有环)。最后的答案是$T(m)=n^{m-2}\prod_{i=1}^{m}v_{i}$.这里要用到prufer编码。对于$m$个联通块的树,其prufer编码的长度为$m-2$。每个位置有$n$种情况,最后乘以叶子节点可以连出的边的数量。

比如$m=3,n=4$,分别是1-2,3,4。那么长度为1的prufer编码可以是{1},{2},{3},{4}.(推导过程参看上面的链接)

对于{1}来说,有两种:第一种: 1-3,1-4, 第二种1-3,2-4

对于{2}来说,有两种:第一种: 2-3,2-4, 第二种2-3,1-4

对于{3}来说,有两种:第一种: 3-1,3-4, 第二种3-2,3-4

对于{4}来说,有两种:第一种: 4-1,4-3, 第二种4-2,4-3

(2)有一个环。那么就要看这个环连通了$m$个联通块中的几个。

第一种: 1个,那么只需要枚举是第几个联通块;

第二种:2个,假设是联通块$a,b$.那么就是$C_{v_av_b}^{2}$

第三种:大于等于3个,假设是$k$个,那么是$\frac{(k-1)!}{2}\prod_{i=1}^{k}v_{ci}^{2}$,其中$ci$第第$i$个选出的联通块的编号。这里除以2是因为有翻转导致重复的情况。比如$k=4$时,$abcd$和$dcab$是一样的。

最后将连成的环看做一个连通分量,那么最后还有$m-k+1$个连通分量,将其连成一个树的方案为$T(m-k+1)$。

 

code for problem1

import java.util.*;
import java.math.*;
import static java.lang.Math.*;

public class TheQuestionsAndAnswersDivOne {
	
	public int find(int n, String[] answers) {

		int[] p = new int[n + 2];
		p[0] = 1;
		for (int i = 1; i < p.length; ++ i) {
			p[i] = p[i - 1] * 3;
		}

		int[][] f = new int[answers.length][p[n]];
		for (int i = 0; i < n; ++ i) {
			int t = answers[0].equals("No")? 1 : 2;
			f[0][t * p[i]] = 1;
		}
		for (int i = 1; i < answers.length; ++ i) {
			int t = answers[i].equals("No")? 1 : 2;
			for (int k = 0; k < p[n]; ++ k) {
				if (f[i - 1][k] == 0) {
					continue;
				}
				for (int j = 0; j < n; ++ j) {
					int x = k / p[j] % 3;
					if (x == 0 || x == t) {
						int nk = k;
						if (x == 0) {
							nk += t * p[j];
						}
						f[i][nk] += f[i - 1][k];
					}
				}
			}
		}
		int result = 0;
		for (int i = 0; i < p[n]; ++ i) {
			boolean tag = true;
			for (int j = 0; j < n; ++ j) {
				if (i / p[j] % 3 == 0) {
					tag = false;
					break;
				}
			}
			if (tag) {
				result += f[answers.length - 1][i];
			}
		}
		return result;
	}
}

  

code for problem2

import java.util.*;
import java.math.*;
import static java.lang.Math.*;

public class TheFansAndMeetingsDivOne {
	
	public double find(int[] minJ, int[] maxJ, int[] minB, int[] maxB, int k) {
		final int n = minJ.length;
		int s1 = 0, s2 = 0;
		for (int i = 0; i < n; ++ i) {
			s1 += maxJ[i];
			s2 += maxB[i];
		}
		final int m = Math.min(s1, s2) + 1;
		double[][][] f = new double[n][k + 1][m];
		double[][][] g = new double[n][k + 1][m];


		f[0][0][0] = 1 - 1.0 * k / n;
		for (int i = minJ[0]; i <= maxJ[0] && i < m; ++ i) {
			f[0][1][i] = 1.0 * k / n / (maxJ[0] - minJ[0] + 1);
		}
		g[0][0][0] = 1 - 1.0 * k / n;
		for (int i = minB[0]; i <= maxB[0] && i < m; ++ i) {
			g[0][1][i] = 1.0 * k / n / (maxB[0] - minB[0] + 1);
		}

		for (int i = 1; i < n; ++ i) {
			for (int j = 0; j <= i && j <= k; ++ j) {
				final double p = 1.0 * (k - j) / (n - i);
				final double p1 = p / (maxJ[i] - minJ[i] + 1);
				final double p2 = p / (maxB[i] - minB[i] + 1);
				for (int t = 0; t < m; ++ t) {
					f[i][j][t] += f[i - 1][j][t] * (1 - p);
					g[i][j][t] += g[i - 1][j][t] * (1 - p);
					if (j == k) {
						continue;
					}
					for (int x = minJ[i]; x <= maxJ[i] && x + t < m; ++ x) {
						f[i][j + 1][x + t] += f[i - 1][j][t] * p1;
					}
					for (int x = minB[i]; x <= maxB[i] && x + t < m; ++ x) {
						g[i][j + 1][x + t] += g[i - 1][j][t] * p2;
					}
				}
			}
		}

		double result = 0;
		for (int i = 0; i < m; ++ i) {
			result += f[n - 1][k][i] * g[n - 1][k][i];
		}
		return result;
	}
}

  


code for problem3

import java.util.*;
import java.math.*;
import static java.lang.Math.*;

public class TheCitiesAndRoadsDivOne {

	static final int MOD = 1234567891;

	public int find(String[] map) {
		final int n = map.length;
		UnionSet unionSet = new UnionSet(n);
		for (int i = 0; i < n; ++ i) {
			for (int j = i + 1; j < n; ++ j) {
				if (map[i].charAt(j) == 'Y') {
					unionSet.merge(i, j);
				}
			}
		}
		List<Integer> list = new ArrayList<>();
		int m = 0;
		int circleNum = 0;
		for (int i = 0; i < n; ++ i) {
			if (unionSet.get(i) == i) {
				++ m;
				list.add(unionSet.vertexNum[i]);
				circleNum += unionSet.edges[i] - unionSet.vertexNum[i] + 1;
			}
		}
		if (circleNum > 1) {
			return 0;
		}

		if (m == 1) {
			if (circleNum == 1 || list.get(0) <= 2) {
				return 1;
			}
			return list.get(0) * (list.get(0) - 1) / 2 - (list.get(0) - 1) + 1;
		}

		long[] p = new long[n + 1];
		p[0] = 1;
		for (int i = 1; i <= n; ++ i) {
			p[i] = p[i-1] * n % MOD;
		}
		long result = p[m - 2];
		for (int i = 0; i < m; ++ i) {
			result = result * list.get(i) % MOD;
		}
		if (circleNum == 1) {
			return (int)result;
		}

		int sum = 0;
		for (int i = 0; i < m; ++ i) {
			int t = list.get(i);
			sum += t * (t - 1) / 2 - (t - 1);
		}
		result = result * (sum + 1) % MOD;

		for (int i = 0; i < (1 << m); ++ i) {
			int cnt = 0;
			for (int j = 0; j < m; ++ j) {
				if ((i & (1 << j)) != 0) {
					++ cnt;
				}
			}
			if (cnt < 2) {
				continue;
			}
			long tmp = 1;
			if (cnt == 2) {
				for (int j = 0; j < m; ++ j) {
					if ((i & (1 << j)) != 0) {
						tmp *= list.get(j);
					}
				}
				tmp = tmp * (tmp - 1) / 2;
			}
			else {
				for (int j = 3; j <= cnt - 1; ++ j) {
					tmp = tmp * j % MOD;
				}
				for (int j = 0; j < m; ++ j) {
					if ((i & (1 << j)) != 0) {
						tmp = tmp * list.get(j) * list.get(j) % MOD;
					}
				}
			}
			if (cnt == m) {
				result = (result + tmp) % MOD;
				continue;
			}
			tmp = tmp * p[(m - cnt + 1) - 2] % MOD;
			long totVertex = 0;
			for (int j = 0; j < m; ++ j) {
				if ((i & (1 << j)) != 0) {
					 totVertex += list.get(j);
				}
				else {
					tmp = tmp * list.get(j) % MOD;
				}
			}
			tmp = tmp * totVertex % MOD;
			result = (result + tmp) % MOD;
		}
		return (int)result;
	}

	static class UnionSet {
		int[] father = null;
		int[] edges = null;
		int[] vertexNum = null;

		UnionSet(int n) {
			father = new int[n];
			edges = new int[n];
			vertexNum = new int[n];
			for (int i = 0; i < n; ++ i) {
				father[i] = i;
				edges[i] = 0;
				vertexNum[i] = 1;
			}
		}

		int get(int u) {
			if (father[u] == u) {
				return u;
			}
			return father[u] = get(father[u]);
		}

		void merge(int u, int v) {
			int fu = get(u);
			int fv = get(v);
			++ edges[fu];
			if (fu == fv) {
				return;
			}
			father[fv] = fu;
			vertexNum[fu] += vertexNum[fv];
			edges[fu] += edges[fv];
		}
	}
}

  

 

posted @ 2017-11-03 22:24  朝拜明天19891101  阅读(242)  评论(0编辑  收藏  举报