1. 程式人生 > >【題解】CF#175(Div. 2) E-Positions in Permutations

【題解】CF#175(Div. 2) E-Positions in Permutations

clas for mes 轉移 () read 完美 define return

  挺有收獲的一道題ヾ(?°∇°?)??

  恰好為 m ,這個限制仿佛不是很好處理。一般而言,我所了解的恰好為 k 的條件,不是用組合數 / dp狀態轉移 / 斜率二分就只剩下容斥了。我們可以先處理出 num[i] 表示至少有 i 個完美位置的方案數,之後再容斥得到 ans[m] (恰好為 m 個)。如何獲得 num 數組?建立dp狀態為 f[i][j][p][q], (其中p, q為01狀態)表示dp到第 i 個位置,已經出現了 j 個完美的位置,且 i 和 i + 1 是否被用過。轉移的時候分情況討論:1.當前位置不成為完美的位置,直接忽略;2.當前位置填 i - 1 成為一個完美的位置;3.當前位置填 i + 1 成為一個完美的位置。之後把忽略掉的數乘上排列數即可。

  這個狀態並不是很好想到,但我們主要要明確:第 i 個位置是否成為完美的位置,僅僅與 i - 1 和 i + 1 有關,而也僅有 i + 1 對於後一個位置存在影響。忽略的數字我們可以直接跳過不算,因為當前不用這個數字 i , i 在之後也無法再影響到完美數的形成。至於容斥,我還是只會 \(n^{2}\) 的由至少到恰好的遞推……這個 O(n) 的全背背式子吧 :(

 \(ans[m] = num[m] - C(m + 1, m) * num[m + 1] ... * (-1)^{n - m} * C(n, m) * num[n]\)

#include <bits/stdc++.h>
using
namespace std; #define maxn 1500 #define int long long #define mod 1000000007 int n, K, f[maxn][maxn][2][2], num[maxn]; int ans[maxn], fac[maxn], C[maxn][maxn]; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < 0 || c > 9) { if(c == -) k = -1; c = getchar(); }
while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar(); return x * k; } void Up(int &x, int y) { x = (x + y) % mod; } void pre() { fac[0] = 1; for(int i = 1; i < maxn; i ++) fac[i] = fac[i - 1] * i % mod; for(int i = 0; i < maxn; i ++) C[i][0] = 1; for(int i = 1; i < maxn; i ++) for(int j = 1; j < maxn; j ++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod; } signed main() { pre(); n = read(), K = read(); f[0][0][1][0] = 1; for(int i = 0; i < n; i ++) { for(int j = 0; j <= i; j ++) for(int p = 0; p <= 1; p ++) for(int q = 0; q <= 1; q ++) { Up(f[i + 1][j][q][0], f[i][j][p][q]); if(!p) Up(f[i + 1][j + 1][q][0], f[i][j][p][q]); if(i < n - 1) Up(f[i + 1][j + 1][q][1], f[i][j][p][q]); } } for(int i = 0; i <= n; i ++) { for(int p = 0; p <= 1; p ++) for(int q = 0; q <= 1; q ++) Up(num[i], f[n][i][p][q]); num[i] = num[i] * fac[n - i] % mod; } ans[K] = num[K]; for(int i = K + 1, t = -1; i <= n; i ++, t *= -1) Up(ans[K], (t * C[i][K] * num[i] % mod) + mod); /*for(int i = n; i >= K; i --) { int t = num[i]; for(int j = n; j > i; j --) t = (t - (ans[j] * C[j][i]) % mod + mod) % mod; ans[i] = t; }*/ printf("%lld\n", ans[K]); return 0; }

【題解】CF#175(Div. 2) E-Positions in Permutations