Codeforces Gym 100338H High Speed Trains 组合数学+dp+高精度
原题链接:http://codeforces.com/gym/100338/attachments/download/2136/20062007-winter-petrozavodsk-camp-andrew-stankevich-contest-22-asc-22-en.pdf
题意
给你n个点,让你连边,使得每个点的度至少为1,问你方案数。
题解
从正面考虑非常困难,应从反面考虑,取 i 点出来不连,这样的取法一共有C(n,i)种取法,其他的连好,而这样就是子问题了。那么dp[n]=2^(n*(n-1)/2)-sum(C(n,i)*dp[n-i])-1,2<=i<=n-1
代码
import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.math.BigInteger; import java.util.*; public class Main { static int n; static BigInteger dp[] = new BigInteger[110]; static BigInteger c[][] = new BigInteger[110][110]; static BigInteger ps[] = new BigInteger[10010]; static BigInteger x; public Main() throws FileNotFoundException{ Scanner cin = new Scanner(new File("trains.in")); PrintWriter cout = new PrintWriter(new File("trains.out")); n = cin.nextInt(); //System.out.println("n = " + n); for(int i=1;i<=100;i++){ c[i][0] = new BigInteger("1"); c[i][1] = new BigInteger(Integer.toString(i)); c[i][i] = new BigInteger("1"); } for(int i=2;i<=100;i++){ for(int j=2;j<i;j++){ c[i][j] = c[i-1][j].add(c[i-1][j-1]); } } ps[0] = new BigInteger("1"); for(int i=1;i<=10001;i++){ ps[i] = ps[i-1].multiply(new BigInteger("2")); } dp[2] = new BigInteger("1"); dp[3] = new BigInteger("4"); for(int i=4;i<=n;i++){ x = new BigInteger("0"); for(int j=2;j<=i-1;j++){ x = x.add(c[i][i-j].multiply(dp[j])); } x = x.add(new BigInteger("1")); dp[i] = ps[i*(i-1)/2].subtract(x); } cout.println(dp[n]); //System.out.println(dp[n]); cin.close(); cout.close(); } public static void main(String[] args) throws FileNotFoundException { new Main(); } }