Description
A girl named Sonya is studying in the scientific lyceum of the Kingdom of Kremland. The teacher of computer science (Sonya's favorite subject!) invented a task for her.
Given an array \(a\) of length \(n\), consisting only of the numbers \(0\) and \(1\), and the number \(k\). Exactly \(k\) times the following happens:
Two numbers \(i\) and \(j\) are chosen equiprobable such that (\(1≤i<j≤n\)).
The numbers in the \(i\) and \(j\) positions are swapped.
Sonya's task is to find the probability that after all the operations are completed, the a array will be sorted in non-decreasing order. She turned to you for help. Help Sonya solve this problem.
It can be shown that the desired probability is either 0 or it can be represented as \(\frac{P}{Q}\), where \(P\) and \(Q\) are coprime integers and \(Q \not\equiv 0\ (\text{mod}\ 10^9+7)\).
Input
The first line contains two integers \(n\) and \(k\) (\(2≤n≤100,1≤k≤10^9\)) — the length of the array \(a\)
and the number of operations.
The second line contains \(n\) integers \(a_1,a_2, \dots ,a_n\) (\(0≤a_i≤1\)) — the description of the array \(a\).
Output
If the desired probability is \(0\), print \(0\), otherwise print the value \(P⋅Q^{−1}\ (\text{mod}\ 10^9+7)\), where \(P\) and \(Q\) are defined above.
Examples
Input
3 2
0 1 0
Output
333333336
Input
5 1
1 1 1 0 0
Output
0
Input
6 4
1 0 0 1 1 0
Output
968493834
Solution
设\(n\)个数中\(0\)的个数为\(a\),\(1\)的个数为\(b\),用\(d_{i, j}\)表示完成\(i\)次操作后,能使前\(a\)个数字中有\(j\)个\(1\)的操作序列的数量,设原数组中,前\(a\)个数字里有\(c\)个\(0\),则我们将\(d_{0,c}\)初始化为1,问题的答案为\(\displaystyle\frac{d_{k, a}}{\sum_{i=0}^{a}d_{k, i}}\)
现在考虑转移,\(d_{i, j}\)可以从\(d_{i - 1, j - 1}\)、\(d_{i-1,j}\)和\(d_{i-1,j +1}\)转移而来
- \(d_{i-1,j}\):或者前\(a\)个数中的两个交换,或者后\(b\)个数中的两个交换,或者前\(a\)个数中的\(0\)与后\(b\)个数中的\(0\)交换,或者前\(a\)个数中的\(1\)与后\(b\)个数中的\(1\)交换
- \(d_{i-1,j-1}\):前\(a\)个数中的\(1\)与后\(b\)个数中的\(0\)交换
- \(d_{i-1,j+1}\):前\(a\)个数中的\(0\)与后\(b\)个数中的\(1\)交换
所以得到转移函数:
\[ \begin{aligned} d_{i,j} = &d_{i-1,j} * \left(\text{C}(a,2) + \text{C}(b,2) + j*(a-j) + (a-j)*(b-a+j)\right)\\ &d_{i-1,j-1} * \left(a-j+1\right)*(a-j+1)\\ &d_{i-1,j+1} *(j+1)*(b-a+j+1) \end{aligned} \]
由于\(d_{i}\)只跟\(d_{i-1}\)有关,且转移函数中的系数与\(i\)无关,所以可以用矩阵快速幂来求\(d_{k}\),复杂度\(O(n^3 \log k)\)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9 + 7;
struct SquareMatrix {
SquareMatrix(int _n) : n(_n) {
data.assign(_n, vector<ll>(_n, 0));
}
vector<ll> &operator[](int i) {
return data[i];
}
const vector<ll> &operator[](int i) const {
return data[i];
}
SquareMatrix operator*(const SquareMatrix &other) const {
assert(n == other.n);
SquareMatrix ret(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
ret[i][j] = (ret[i][j] + data[i][k] * other[k][j]) % mod;
}
}
}
return ret;
}
vector<vector<ll>> data;
int n;
};
SquareMatrix quickpower(SquareMatrix m, int p) {
int n = m.n;
SquareMatrix ret(n);
for (int i = 0; i < n; ++i) ret[i][i] = 1;
while (p) {
if (p & 1) {
ret = ret * m;
}
m = m * m;
p >>= 1;
}
return ret;
}
ll quickpower(ll x, int p) {
ll ret = 1;
while (p) {
if (p & 1) ret = (ret * x) % mod;
x = (x * x) % mod;
p >>= 1;
}
return ret;
}
int main() {
int n, k;
scanf("%d%d", &n, &k);
vector<int> a(n);
int x = 0, y = 0, z = 0;
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
x += a[i] == 0;
}
y = n - x;
for (int i = 0; i < x; ++i)
z += a[i] == 0;
if (x > y) { // 如果0的个数大于1的个数,可以反向处理数组
swap(x, y);
z = 0;
for (int i = n - 1; i >= n - x; --i)
z += a[i] == 1;
}
SquareMatrix m(x + 1);
for (int i = 0; i <= x; ++i) {
m[i][i] = x * (x - 1) / 2 + y * (y - 1) / 2 + i * (x - i) + (x - i) * (y - x + i);
if (i - 1 >= 0) m[i][i - 1] = (x - i + 1) * (x - i + 1);
if (i + 1 <= x) m[i][i + 1] = (i + 1) * (y - x + i + 1);
}
m = quickpower(m, k);
ll ans = 0;
for (int i = 0; i <= x; ++i)
ans = (ans + m[i][z]) % mod;
ans = m[x][z] * quickpower(ans, mod - 2) % mod;
printf("%I64d\n", ans);
return 0;
}