我们考虑每个向左的点, 从左往右进行转移。
f[ i ][ j ] 表示前 i 个点攻击完之后, 剩下 j 个点向右移动的概率。
考虑转移
f[ i ][ j ] = sum(f[ i - 1 ][ k ] * 2 ^ (k - j - 1)) k >= j
f[ i ][ 1 ] += sum(f[ i - 1 ][ j ] * 2 ^ (-j)
第一个转移显然可以优化到o(1)
#pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0) using namespace std; const int N = 1e3 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = (int)1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;} int n; int inv2 = mod / 2 + 1; int ibin[N]; int bin[N]; int a[N]; int f[N][N]; int g[N][N]; int dp[N]; int power(int a, int b) { int ans = 1; while(b) { if(b & 1) ans = 1LL * ans * a % mod; a = 1LL * a * a % mod; b >>= 1; } return ans; } int main() { for(int i = ibin[0] = bin[0] = 1; i < N; i++) { ibin[i] = 1LL * ibin[i - 1] * inv2 % mod; bin[i] = 1LL * bin[i - 1] * 2 % mod; } int T, cas = 0; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { f[i][j] = g[i][j] = 0; } } for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } if(n == 1) { printf("Case #%d: 1\n", ++cas); continue; } a[n] = 0; int pre = -1; for(int i = 1; i <= n; i++) { if(a[i] == 1) continue; dp[i] = 0; if(pre == -1) { if(i == 1) { dp[i] = 1; f[i][1] = 1; } else { dp[i] = ibin[i - 1]; for(int j = 1; j <= i - 1; j++) { if(j == 1) f[i][j] = 2 * ibin[i - 1] % mod; else f[i][j] = ibin[i - j]; } } } else { int c = i - pre - 1; for(int j = n - 1; j >= 1; j--) { if(j - c > 0) f[pre][j] = f[pre][j - c]; else f[pre][j] = 0; g[pre][j] = (g[pre][j + 1] + 1LL * f[pre][j] * ibin[j] % mod) % mod; } for(int j = 1; j < n; j++) { f[i][j] = 1LL * g[pre][j] * bin[j - 1] % mod; } for(int j = 1; j < n; j++) { add(f[i][1], 1LL * f[pre][j] * ibin[j] % mod); add(dp[i], 1LL * f[pre][j] * ibin[j] % mod); } } pre = i; } printf("Case #%d: %d\n", ++cas, dp[n]); } return 0; } /* */