题目链接:http://codeforces.com/problemset/problem/1151/F
题目大意:
给定长度为 n 的 01 序列,可以对该序列操作 k 次,每次操作可以交换序列中任意两个元素的位置,求进行 k 次操作后 01 序列升序排列的概率。
分析:
- 交换后 j 减少,即 dp[i + 1][j - 1],必然是左边的 0 和右边的 1 交换,因此 dp[i + 1][j - 1] = dp[i][j] * j * (cnt_1 - cnt_0 + j)。
- 交换后 j 不变,即 dp[i + 1][j],有三种可能,(1)0 与 0 之间交换,有 $inom{cnt_0}{2}$ 种;(2)1 与 1 之间交换,有 $inom{cnt_1}{2}$ 种;(3)同一边的 0 与 1 之间交换,有 j * (cnt_0 - j) + (cnt_0 - j) * (cnt_1 - cnt_0 + j) 种;因此 dp[i + 1][j + 1] = dp[i][j] * ($inom{cnt_0}{2}$ + $inom{cnt_1}{2}$ + j * (cnt_0 - j) + (cnt_0 - j) * (cnt_1 - cnt_0 + j))。
- 交换后 j 增加,即 dp[i + 1][j + 1],必然是左边的 1 和右边的 0 交换,因此 dp[i + 1][j + 1] = dp[i][j] * (cnt_0 - j) * (cnt_0 - j)。
整理一下得到递推公式:dp[i][j] = dp[i - 1][j - 1] * (cnt_0 - j + 1) * (cnt_0 - j + 1)
+ dp[i - 1][j] * ($inom{cnt_0}{2}$ + $inom{cnt_1}{2}$ + j * (cnt_0 - j) + (cnt_0 - j) * (cnt_1 - cnt_0 + j))
+ dp[i - 1][j + 1] * (j + 1) * (cnt_1 - cnt_0 + j + 1)
设 para0(j) = (cnt_0 - j + 1) * (cnt_0 - j + 1)。
设 para1(j) = ($inom{cnt_0}{2}$ + $inom{cnt_1}{2}$ + j * (cnt_0 - j) + (cnt_0 - j) * (cnt_1 - cnt_0 + j))。
设 para2(j) = (j + 1) * (cnt_1 - cnt_0 + j + 1)。
于是 dp[i][j] = dp[i - 1][j - 1] * para0(j) + dp[i - 1][j] * para1(j) + dp[i - 1][j + 1] * para2(j)。
由于 i 只依赖 i - 1 以及与 i 无关的参数项,可以考虑矩阵快速幂求解,构造如下矩阵(以cnt_0 = 4 为例):
$$
X = egin{bmatrix}
para1(0) & para0(1) & 0 & 0 & 0 \
para2(0) & para1(1) & para0(2) & 0 & 0 \
0 & para2(1) & para1(2) & para0(3) & 0 \
0 & 0 & para2(2) & para1(3) & para0(4) \
0 & 0 & 0 & para2(3) & para1(4)
end{bmatrix} ag{1}
$$
再构造如下答案矩阵:
$$
ans(i) = egin{bmatrix}
dp[i][0] & dp[i][1] & dp[i][2] & dp[i][3] & dp[i][4]
end{bmatrix} ag{2}
$$
不难看出,ans(i) 与 X 有如下关系:
$$
ans(i) = ans(i - 1) * X \
ans(i) = ans(0) * X^i
ag{3}
$$
于是利用矩阵快速幂即可求出 P。
按照题目要求,再对 Q 用扩展欧几里得算法求一下逆元就差不多了。
代码如下:
1 #pragma GCC optimize("Ofast") 2 #include <bits/stdc++.h> 3 using namespace std; 4 5 #define INIT() std::ios::sync_with_stdio(false);std::cin.tie(0); 6 #define Rep(i,n) for (int i = 0; i < (n); ++i) 7 #define For(i,s,t) for (int i = (s); i <= (t); ++i) 8 #define rFor(i,t,s) for (int i = (t); i >= (s); --i) 9 #define ForLL(i, s, t) for (LL i = LL(s); i <= LL(t); ++i) 10 #define rForLL(i, t, s) for (LL i = LL(t); i >= LL(s); --i) 11 #define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) 12 #define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i) 13 14 #define pr(x) cout << #x << " = " << x << " " 15 #define prln(x) cout << #x << " = " << x << endl 16 17 #define LOWBIT(x) ((x)&(-x)) 18 19 #define ALL(x) x.begin(),x.end() 20 #define INS(x) inserter(x,x.begin()) 21 22 #define ms0(a) memset(a,0,sizeof(a)) 23 #define msI(a) memset(a,inf,sizeof(a)) 24 #define msM(a) memset(a,-1,sizeof(a)) 25 26 #define MP make_pair 27 #define PB push_back 28 #define ft first 29 #define sd second 30 31 template<typename T1, typename T2> 32 istream &operator>>(istream &in, pair<T1, T2> &p) { 33 in >> p.first >> p.second; 34 return in; 35 } 36 37 template<typename T> 38 istream &operator>>(istream &in, vector<T> &v) { 39 for (auto &x: v) 40 in >> x; 41 return in; 42 } 43 44 template<typename T1, typename T2> 45 ostream &operator<<(ostream &out, const std::pair<T1, T2> &p) { 46 out << "[" << p.first << ", " << p.second << "]" << " "; 47 return out; 48 } 49 50 typedef long long LL; 51 typedef unsigned long long uLL; 52 typedef pair< double, double > PDD; 53 typedef pair< int, int > PII; 54 typedef set< int > SI; 55 typedef vector< int > VI; 56 typedef map< int, int > MII; 57 typedef vector< LL > VL; 58 typedef vector< VL > VVL; 59 const double EPS = 1e-10; 60 const int inf = 1e9 + 9; 61 const LL mod = 1e9 + 7; 62 const int maxN = 1e5 + 7; 63 const LL ONE = 1; 64 const LL evenBits = 0xaaaaaaaaaaaaaaaa; 65 const LL oddBits = 0x5555555555555555; 66 67 struct Matrix{ 68 int row, col; 69 LL MOD; 70 VVL mat; 71 72 Matrix(int r = 1, int c = 4, LL p = mod) : row(r), col(c), MOD(p) { 73 mat.resize(r); 74 Rep(i, r) mat[i].resize(c, 0); 75 } 76 Matrix(const Matrix &x, LL p = mod) : MOD(p){ 77 mat = x.mat; 78 row = x.row; 79 col = x.col; 80 } 81 Matrix(const VVL &A, LL p = mod) : MOD(p){ 82 mat = A; 83 row = A.size(); 84 col = A[0].size(); 85 } 86 87 // x * 单位阵 88 inline void E(int x = 1) { 89 assert(row == col); 90 Rep(i, row) mat[i][i] = x; 91 } 92 93 inline VL& operator[] (int x) { 94 assert(x >= 0 && x < row); 95 return mat[x]; 96 } 97 98 inline Matrix operator= (const Matrix &x) { 99 row = x.row; 100 col = x.col; 101 mat = x.mat; 102 return *this; 103 } 104 105 inline Matrix operator= (const VVL &x) { 106 row = x.size(); 107 col = x[0].size(); 108 mat = x; 109 return *this; 110 } 111 112 inline Matrix operator+ (const Matrix &x) { 113 assert(row == x.row && col == x.col); 114 Matrix ret(row, col); 115 Rep(i, row) { 116 Rep(j, col) { 117 ret.mat[i][j] = mat[i][j] + x.mat[i][j]; 118 ret.mat[i][j] %= MOD; 119 } 120 } 121 return ret; 122 } 123 124 inline Matrix operator* (const Matrix &x) { 125 assert(col == x.row); 126 Matrix ret(row, x.col); 127 Rep(k, col) { 128 Rep(i, row) { 129 if(mat[i][k] == 0) continue; 130 Rep(j, col) { 131 ret.mat[i][j] += mat[i][k] * x.mat[k][j]; 132 ret.mat[i][j] %= MOD; 133 } 134 } 135 } 136 return ret; 137 } 138 139 inline Matrix operator*= (const Matrix &x) { return *this = *this * x; } 140 inline Matrix operator+= (const Matrix &x) { return *this = *this + x; } 141 142 inline void print() { 143 Rep(i, row) { 144 Rep(j, col) { 145 cout << mat[i][j] << " "; 146 } 147 cout << endl; 148 } 149 } 150 }; 151 152 // 矩阵快速幂,计算x^y 153 inline Matrix mat_pow_mod(Matrix x, LL y) { 154 Matrix ret(x.row, x.col); 155 ret.E(); 156 while(y){ 157 if(y & 1) ret *= x; 158 x *= x; 159 y >>= 1; 160 } 161 return ret; 162 } 163 164 // 扩展欧几里得求逆元 165 inline void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){ 166 if (!b) {d = a, x = 1, y = 0;} 167 else{ 168 ex_gcd(b, a % b, y, x, d); 169 y -= x * (a / b); 170 } 171 } 172 173 inline LL inv_mod(LL a, LL p = mod){ 174 LL d, x, y; 175 ex_gcd(a, p, x, y, d); 176 return d == 1 ? (x % p + p) % p : -1; 177 } 178 179 // Calculate x^y % p 180 inline LL pow_mod(LL x, LL y, LL p = mod){ 181 LL ret = 1; 182 while(y){ 183 if(y & 1) ret = (ret * x) % p; 184 x = (x * x) % p; 185 y >>= 1; 186 } 187 return ret; 188 } 189 190 LL n, k, P, Q; 191 int a[107], cnt_0, cnt_1, cnt_00; 192 193 int main(){ 194 INIT(); 195 cin >> n >> k; 196 For(i, 1, n) { 197 cin >> a[i]; 198 a[i] ? ++cnt_1 : ++cnt_0; 199 } 200 For(i, 1, cnt_0) if(!a[i]) ++cnt_00; 201 202 // 构造矩阵 203 Matrix ans(1, cnt_0 + 1); 204 ans[0][cnt_00] = 1; 205 Matrix X(cnt_0 + 1, cnt_0 + 1); 206 Rep(j, cnt_0 + 1) { 207 X[j][j] = (cnt_0 * (cnt_0 - 1) / 2 + cnt_1 * (cnt_1 - 1) / 2 + j * (cnt_0 - j) + (cnt_0 - j) * (cnt_1 - cnt_0 + j)); 208 if(j > 0) X[j - 1][j] = (cnt_0 - j + 1) * (cnt_0 - j + 1); 209 if(j < cnt_0) X[j + 1][j] = (j + 1) * (cnt_1 - cnt_0 + j + 1); 210 } 211 ans *= mat_pow_mod(X, k); 212 P = ans[0][cnt_0]; 213 Q = n * (n - 1) / 2; 214 Q = pow_mod(Q, k); 215 Q = inv_mod(Q); 216 217 cout << (P * Q) % mod << endl; 218 return 0; 219 }