Codeforces 889C Maximum Element(DP + 计数)
題目鏈接??Maximum Element
題意? 現在有這一段求序列中最大值的程度片段:
(假定序列是一個1-n的排列)
int fast_max(int n, int a[]) { int ans = 0;int offset = 0;for (int i = 0; i < n; ++i)if (ans < a[i]) {ans = a[i];offset = 0;} else {offset = offset + 1;if (offset == k)return ans;}return ans; }顯然這段程序是錯誤的……有很多可以X掉這段程序的排列
求這樣的排列有多少個。
題目是讓我們求符合這樣條件的排列個數:
1、存在某個數,他比前面的數都大并且小于$n$;
2、他比他后面$k$個數都要大。
假設“中間這個數”為$cnt$
?
假設$D(i)$為滿足$p(i) = i$的這樣的排列個數
我們可以把$D(i)$的求解分成兩個過程。
1、計算$cnt$等于$i - 1$的排列個數
2、計算$cnt$不等于$i - 1$的排列個數
?
首先如果$i <= k + 1$,則$D(i) = 0$
?
當這個序列的$cnt$為$i - 1$時,只要滿足$i - 1$和$i$之間的數大于等于$k$個即可。
于是對于$i - 1$這個數的位置的選擇,我們有$i - k - 1$種。
然后呢,除了$i - 1$和$i$這兩個數,其他數的位置隨意(因為$i$排在最后,所以排在$i - 1$前的數字都比$i - 1$要小)
所以當前這種情況對答案的貢獻為$(i - k - 1) * (i - 2)!$
?
考慮另外一種情況。
當$cnt$不等于$i - 1$的時候,一定有$cnt < i - 1$
設$i - 1$所在位置為$pos$,我們把$i - 1$之前的$pos - 1$個數離散化成一個$1$到$pos - 1$的排列
然后在這個排列的最后加上$pos$,就構成了一個$1$到$pos$并且以$pos$結尾的排列
那么如果這個排列是符合要求的,那么整個排列也是符合要求的。
于是我們枚舉$i - 1$的位置$pos$,滿足條件的位置為$i - k <= pos <= i - 1$
我們在剩下的$i - 2$個數中選出$pos - 1$個放到前$pos - 1$個位置,然后乘上$D(pos)$。
然后還要乘上$(i - pos - 1)!$,因為$i - 1$到$i$之間的數都是隨意亂放的……
于是當前這種情況對答案的貢獻為
于是我們終于推出了D(n)的公式
最后的答案怎么計算呢
我們假設$n$的位置為$pos$
那么當$p(pos) = n$的時候,前pos個數的方案數為$D(pos) * C(n - 1, pos - 1)$
后$n - pos$個數的方案數為$(n - pos)!$
所以當$p(pos) = n$的時候對答案的貢獻為$D(pos) * C(n - 1, pos - 1)*(n - pos)!$
枚舉$pos$,累加即可。
?
#include <bits/stdc++.h>using namespace std;#define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i)const int N = 1e6 + 10; const int mod = 1e9 + 7; int n, k; int f[N], s[N]; int fac[N], inv[N]; int ans = 0;inline int Pow(int a, int b, int mod){int ret(1);for (; b; b >>= 1, a = (1ll * a * a) % mod) if (b & 1) (ret = 1ll * ret * a) % mod;return ret; } void init(){fac[0] = 1;rep(i, 1, 1e6 + 1) fac[i] = 1ll * fac[i - 1] * i % mod;rep(i, 1, 1e6 + 1) inv[i] = Pow(fac[i], mod - 2, mod); }inline void up(int &a, int b) { a = (0ll + a + b) % mod;} inline void mulup(int &a, int b){ a = 1ll * a * b % mod;}int main(){scanf("%d%d", &n, &k);init();rep(i, k + 2, n){f[i] = i - k - 1;up(f[i], s[i - 1] - s[i - k - 1]);mulup(f[i], fac[i - 2]);s[i] = (0ll + s[i - 1] + 1ll * f[i] * inv[i - 1] % mod) % mod;}rep(i, 1, n) up(ans, (int)1ll * f[i] * fac[n - 1] % mod * inv[i - 1] % mod);printf("%d\n", ans);return 0; }?
?
轉載于:https://www.cnblogs.com/cxhscst2/p/7935561.html
總結
以上是生活随笔為你收集整理的Codeforces 889C Maximum Element(DP + 计数)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux (ubuntu)安装pych
- 下一篇: 为什么说国家助学贷款是信用贷款