zoukankan      html  css  js  c++  java
  • HDU2048神、上帝以及老天爷

    1. 题面

    2. 解法

    • 错排公式
      (N)个编号元素放在(N)个编号位置,求元素编号和位置编号不相同的方案数。这样的问题我们称为错排问题
      递推公式$$D[n] = (n-1)*[D[n-1]+D[n-2]]$$
      其中(D[n])表示方案数
      下面给出证明:
      第一步,把第(n)个元素放在一个位置上,有(n-1)种放法
      第二步,放第(k)个元素时,有两种情况。(1)放在第n号位置时,剩下的(n-2)个元素有(D[n-2])种方法。(2)不放在n号位置时,这(n-1)个元素有(n-1)种放置方法。
      由加法原理和乘法原理得:

    [D[n] = (n-1)*[D[n-1]+D[n-2]] ]

    接下来的事情就非常简单了,只需要递归计算(D[n]),然后除(n!)即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    unsigned long long fact[21];
    
    unsigned long long dfs(int n)
    {
    	if(n == 1) return 0;
    	if(n == 2) return 1;
    	return (n - 1) *(dfs(n - 2) + dfs(n - 1));
    }
    
    int main()
    {
    	int cnt,t;
    	
    	fact[1] = 1;
    	for(int i = 2;i <= 20;i ++ )
    	{
    		fact[i] = fact[i - 1] * i;
    	}
    	
    	cin >> t;
    	for(int i = 1;i <= t;i ++ )
    	{
    		cin >> cnt;
    		cout << fixed << setprecision(2) << dfs(cnt) * 1.0 / fact[cnt] * 100 << "%" << endl;
    	}
    	return 0;
    }
    
    • 容斥原理
      正整数(1, 2, 3,cdots, n)的全排列有(n!)种,其中第(k)位是(k)的排列有((n-1)!)种;当(k)分别取(1, 2, 3,cdots, n)时,共有(n*(n-1)!)种排列是至少放对了一个的,由于所求的是错排的种数,所以应当减去这些排列;但是此时把同时有两个数不错排的排列多排除了一次,应补上;在补上时,把同时有三个数不错排的排列多补上了一次,应排除;(cdotscdots);继续这一过程,得到错排的排列种数为

    [D(n) = n! - frac{n!}{1!} + frac{n!}{2!} - frac{n!}{3!} + cdots + frac{{-1}^{n}*n!}{n!} = sum_{k=2}^{n}frac{{-1}^{k} * n!}{k!} ]

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    long long b[21];
    int main()
    {
    	b[1] = 1;
    	for(int i = 2;i <= 20;i ++ )
    	{
    		b[i] = b[i - 1] * i;
    	}
    	
    	int t;
    	cin >> t;
    	for(int i = 1;i <= t;i ++ )
    	{
    		long long sum = 0;
    		cin >> n;
    		for(int k = 2;k <= n;k ++ )
    		{
    			sum += (pow(-1,k) * b[n]) / b[k];
    		}
    		cout << fixed << setprecision(2) << ((sum * 1.0) / b[n]) * 100 << "%" << endl;
    	}
    	return 0;
    }
    
    • 错排公式
      这个东西是

    [D(n)= [frac{n!}{e}+0.5] ]

    具体怎么证明我也不太清楚,高数还没学到,贴一下百度百科上的证明好力(
    证明:
    由于$$frac{1}{e} = e^{-1} = frac{1}{0!} - frac{1}{1!} + frac{1}{2!} - frac{1}{3!} - cdots + frac{{-1}^{n}}{n!} + Rn(-1)$$,
    其中(Rn(-1))是余项,等于(frac{{-1}^{n+1} * e^u}{(n+1)!}),且(u in (-1, 0)).
    所以,$$D(n) = n! * {e}^{-1} - frac{{-1}^{n+1} * e^u}{(n+1)},u∈(-1, 0)$$
    而$$|n! Rn| = |frac{{-1}^{n+1} * {e}^{u}}{n+1}| = frac{{e}^{u}}{n+1} in (frac{1}{[e(n+1)]}, frac{1}{(n+1)})$$可知即使在(n=1)时,该余项(的绝对值)也小于(frac{1}{2})
    因此,无论(n! Rn)是正是负,(frac{n!}{e} + frac{1}{2})的整数部分都一定与M(n)相同。

    #include<bits/stdc++.h>
    using namespace std;
    #define e 2.718281828459 
    int main()
    {
    	int n,m,t;
    	double a[21] = {1,1,2,6};
    	long long b[21] = {0,0,1,2};
    	for(int i = 4;i <= 20;i ++ )
    	{
    		a[i] = a[i - 1] * i;
    		b[i] = (a[i]/e + 0.5);
    	}
    	cin >> t;
    	for(int i = 1;i <= t;i ++ )
    	{
    		cin >> n;
    		printf("%.2lf%%
    ",b[n]/a[n]*100);
    	}
    	return 0;
    }
    

    4. 后记

    哇,这篇写了超长时间,从开始写这个题,然后寻找其他解法,再然后写各种代码,简直是我写过最长时间的一篇了。

  • 相关阅读:
    浅谈MVP与ModelViewViewModel(MVVM)设计模式
    策略模式
    C#验证码
    如何招到烂程序员
    承载和使用WCF服务
    .NET Remoting 使用总结
    基于.Net Remoting的应用程序
    HTML5 是什么?
    关于HTTP及XMLHTTP状态代码一览
    Remoting多个信道(Chennel)的注册问题
  • 原文地址:https://www.cnblogs.com/breadcomplex/p/14123105.html
Copyright © 2011-2022 走看看