JZOJ 5164、【NOIP2017模擬6.25】小A做CF
阿新 • • 發佈:2018-10-04
lds des dst ali 解法 參加 6.2 其它 ()
下面通過這個遞推關系推導通項公式:
為方便起見,設D(k) = k! N(k), k = 1, 2, …, n,
則N(1) = 0, N(2) = 1/2.
n ≥ 3時,n! N(n) = (n-1) (n-1)! N(n-1) + (n-1)! N(n-2)
即 nN(n) = (n-1) N(n-1) + N(n-2)
於是有N(n) - N(n-1) = - [N(n-1) - N(n-2)] / n = (-1/n) [-1/(n-1)] [-1/(n-2)]…(-1/3) [N(2) - N(1)] = (-1)^n / n!.
因此
N(n-1) - N(n-2) = (-1)^(n-1) / (n-1)!,
N(2) - N(1) = (-1)^2 / 2!.
相加,可得
N(n) = (-1)^2/2! + … + (-1)^(n-1) / (n-1)! + (-1)^n/n!
因此
D(n) = n! [(-1)^2/2! + … + (-1)^(n-1)/(n-1)! + (-1)^n/n!].
此即錯排公式。
(簡化:f[i]=(i-1)*(f[i-1]+f[i-2]))
日常吐槽:我......已經不想再說什麽了,8:20還要做初賽然後很心累:)
題目:
題解:
20%爆搜+剪枝
60%爆搜+更好的剪枝來騙分(本驗題人未打過這檔分,所以拿不到的也沒辦法)
100%有兩種方法,一種是原題解方法,一種是本驗題人方法。
法一:錯排公式 (粘貼自百度百科)
遞推公式
當n個編號元素放在n個編號位置,元素編號與位置編號各不對應的方法數用D(n)表示,那麽D(n-1)就表示n-1個編號元素放在n-1個編號位置,各不對應的方法數,其它類推. 第一步,把第n個元素放在一個位置,比如位置k,一共有n-1種方法; 第二步,放編號為k的元素,這時有兩種情況:⑴把它放到位置n,那麽,對於剩下的n-1個元素,由於第k個元素放到了位置n,剩下n-2個元素就有D(n-2)種方法;⑵第k個元素不把它放到位置n,這時,對於這n-1個元素,有D(n-1)種方法; 綜上得到 D(n) = (n-1) [D(n-2) + D(n-1)] 特殊地,D(1) = 0, D(2) = 1.容斥原理
用容斥原理也可以推出錯排公式: 正整數1, 2, 3, ……, n的全排列有 n! 種,其中第k位是k的排列有 (n-1)! 種;當k分別取1, 2, 3, ……, n時,共有n*(n-1)!種排列是至少放對了一個的,由於所求的是錯排的種數,所以應當減去這些排列;但是此時把同時有兩個數不錯排的排列多排除了一次,應補上;在補上時,把同時有三個數不錯排的排列多補上了一次,應排除;……;繼續這一過程,得到錯排的排列種數為 D(n) = n! - n!/1! + n!/2! - n!/3! + … + (-1)^n * n!/n! = ∑(k=2~n) (-1)^k * n! / k!, 即D(n) = n! [1/0! - 1/1! + 1/2! - 1/3! + 1/4! + ... + (-1)^n/n!]. 其中,∑表示連加符號,k=2~n是連加的範圍;0! = 1,可以和1!相消。二項式反演
利用二項式反演我們更為簡便的推導出一個通項公式。 考慮令 表示 個數字任意放的方案數, 表示 個數字都不放在自己位置上的方案數,通過枚舉不在自己位置上的數字的個數容易得到 由二項式反演得到 註意到 ,這樣我們就得到了他的通項公式,通過將 和組合數展開就可以得到更為簡便的通項公式了#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n, w[210][500], p[500], q[500], len = 1, l, k1; void jia(int k) { memset(q, 0, sizeof q); for (int i = 1; i <= len; i++) q[i] = w[k - 2][i] + w[k - 1][i]; for (int i = 1; i <= len; i++) { q[i + 1] += q[i] / 10; q[i] %= 10; } while (q[len + 1]) len++; } void cheng(int k) { jia(k); l = 0, k1 = k; memset(p, 0, sizeof p); while (k1 >= 10) { p[++l] = k1 % 10; k1 /= 10; } if (k1) p[++l] = k1; for (int i = 1; i <= len; i++) for (int j = 1; j <= l; j++) w[k][i + j - 1] += q[i] * p[j]; for (int i = 1; i < len + l; i++) { w[k][i + 1] += w[k][i] / 10; w[k][i] %= 10; } len = len + l - 1; while (w[k][len + 1]) len++; } int main() { memset(w, 0, sizeof w); scanf("%d", &n); w[1][1] = 1; w[2][1] = 2; for (int i = 3; i < n; i++) cheng(i); for (int i = len; i >= 1; i--) printf("%d", w[n - 1][i]); printf("\n"); return 0; }
法二:驗題人解法
基於轉化後的模型,可以發現,對於空白棋盤方案數是相當容易求出來的,而帶障礙棋盤方案可以通過容斥原理實現 (即將總的減去放一個棋子在障礙上再加回兩個棋子在障 礙上……)預處理出組合數(因為放障礙時要選位置),可以得出如下式子:(設有n行n列,m個障礙) Ans=∑(-1) i*C i m*(n-i)!(i 枚舉障礙數,由 0 到 m)
JZOJ 5164、【NOIP2017模擬6.25】小A做CF