RandomPaintingOnABoard

我们考虑对每行没列 $\min-\max$ 容斥。

考虑某种状态(行列的状态)每个集合内部的元素(一行或者一列)出现了一个数的最大时间,也就是全部都有数的时间(类似 [HAOI2015]按位或)。由于式子

也就是我们得算的实际上是每种状态(一些行与列)中的数第一次被选到的期望时间。

如果我们实际枚举了行列的状态,对于每个状态,设这些行列的和是 $x$ ,那么贡献就是 $(-1)^T\frac {tot} {x}$ 这个东西。

因为选到一次的概率是 $\frac x{tot}$ ,期望就是倒数。

但是实际上我们是不能枚举行列的状态的,考虑将行列数量较小的设为 $n$ ,有 $n\le 12$ ,我们可以先暴力枚举行的状态 $2^n$,现在考虑可以做一个背包,$f[0/1][x]$ 表示一共有奇数或者偶数个行列被选择了,现在的贡献和是 $x$ 的选择列的方案数量。由于每个数不超过 $9$ ,而这么做复杂度是 $O(m\sum p_{i,j})$ 的,可以通过。

所以最终时间复杂度 $O(2^nm\sum p)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#include "queue"
using namespace std;
#define MAXN 1000006
//#define int long long
#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all(x) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
typedef long long ll;

const int inf = 1e9;

int n , m;
int A[123][123];
int dp[2][1620];

class RandomPaintingOnABoard {
public:
double expectedSteps( vector<string> str ) {
n = str.size() , m = str[0].size();
int tot = 0;
if( n < m ) {
rep( i , 0 , n - 1 ) rep( j , 0 , m - 1 ) A[i][j] = str[i][j] - '0' , tot += A[i][j];
} else {
swap( n , m );
rep( i , 0 , n - 1 ) rep( j , 0 , m - 1 ) A[i][j] = str[j][i] - '0' , tot += A[i][j];
}
double res = 0;
for( int i = 0 ; i < ( 1 << n ) ; ++ i ) {
int s = 0 , cur = 0;
for( int j = 0 ; j < n ; ++ j ) if( i & ( 1 << j ) ) {
cur ^= 1;
for( int k = 0 ; k < m ; ++k ) s += A[j][k];
}
mem( dp );
dp[cur][s] = 1;
for( int j = 0 ; j < m ; ++ j ) {
int sl = 0;
for( int k = 0 ; k < n ; ++ k ) if( ~i & ( 1 << k ) ) sl += A[k][j];
for( int k = tot ; k >= sl ; -- k ) {
int t0 = dp[0][k - sl] , t1 = dp[1][k - sl];
dp[0][k] += t1 , dp[1][k] += t0;
}
}
for( int j = 1 ; j <= tot ; ++ j ) res += ( dp[1][j] - dp[0][j] ) * tot * 1. / j;
}
return res;
}
} F ;

//int main() {
// vector<string> in {"10", "01"};
// cout << F.expectedSteps( in );
//}
文章作者: yijan
文章链接: https://yijan.co/randompaintingonaboard/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog