Link with EQ
题目大意:有 n n n 个座位,起初第一个人会随机挑选一个位置坐下,后来的人会挑一个离最近的人最远的位置坐下,当无论挑什么位置旁边( + 1 +1 +1 或 − 1 -1 −1 的位置)都已经坐了人的话,结束。
这题的难点在于,每个人会选择一个离最近的人最远的位置,这个位置可能有多个,虽然概率是相等的,但是倘若我们不知道具体的状态我们就算不出来这样的位置有几个,但是我们显然不可能去考虑具体的状态。所以我们就想,是否有定住的状态,也就是先去计算某个人下一次一定会坐某个位置的状态,最终看看这样的状态能否用于计算所有的状态,神奇的是,确实可以。
设
f
i
f_i
fi 表示一共有
i
i
i 个凳子,且凳子两端都已经坐了人,其它位置为空,在此为初始状态下的一共可以坐的人的期望
(
i
>
1
)
(i>1)
(i>1)
那么首先我们有
f
3
=
f
4
=
2
f_3=f_4=2
f3=f4=2,对于其它情况,我们设
j
=
(
i
+
1
)
/
2
j=(i+1)/2
j=(i+1)/2 ,显然这样的情况下一个人只会坐中间,则有:
f
i
=
f
j
+
f
i
+
1
−
j
−
1
f_i=f_j+f_{i+1-j}-1
fi=fj+fi+1−j−1
注:这里其实对于
i
i
i 为偶数的情况是可以有两种选择的,但是这两种情况完全一样,概率又相同,所以直接计算某一种即可。
设
g
i
g_i
gi 表示一共有
i
i
i 个凳子,且凳子的一端坐了人,其它位置为空,在此为初始状态下的一共可以坐的人的期望
那么我们首先有
g
1
=
g
2
=
1
g_1=g_2=1
g1=g2=1 ,对于其它情况,下一个人必然坐另一个端点,则我们有:
g
i
=
f
i
g_i=f_i
gi=fi
设
h
n
h_n
hn 表示一共有
n
n
n 个凳子,所有位置都为空,在此为初始状态下一共可以坐的人的期望。
h
1
=
1
h_1=1
h1=1
h
n
=
∑
i
=
1
n
1
n
(
g
i
+
g
n
+
1
−
i
−
1
)
=
1
n
∑
i
=
1
n
(
g
i
+
g
n
+
1
−
i
−
1
)
=
2
n
(
∑
i
=
1
n
g
i
)
−
1
h_n=\sum\limits_{i=1}^n\frac{1}{n}(g_i+g_{n+1-i}-1)=\frac{1}{n}\sum\limits_{i=1}^n(g_i+g_{n+1-i}-1)=\frac{2}{n}(\sum\limits_{i=1}^ng_i)-1
hn=i=1∑nn1(gi+gn+1−i−1)=n1i=1∑n(gi+gn+1−i−1)=n2(i=1∑ngi)−1
所以我们只要处理出 g i g_i gi 的前缀和,我们就可以求得所有的答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const ll mod = 1e9 + 7;
int n;
ll inv[N];
ll f[N], sumg[N], h[N];
ll ksm(ll base, ll n) {
ll ans = 1;
while(n) {
if (n & 1ll) ans = ans * base % mod;
base = base * base % mod;
n >>= 1ll;
}
return ans;
}
void init(int n) {
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = ksm(i, mod - 2);
}
f[3] = f[4] = 2;
for (int i = 5; i <= n; ++i) {
int j = (i + 1) / 2;
f[i] = (f[j] + f[i + 1 - j] - 1 + mod) % mod;
}
sumg[1] = 1; sumg[2] = 2;
for (int i = 3; i <= n; ++i) {
sumg[i] = (sumg[i - 1] + f[i]) % mod;
}
h[1] = 1;
for (int i = 2; i <= n; ++i) {
h[i] = (2ll * inv[i] % mod * sumg[i] % mod - 1 + mod) % mod;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
init(1e6);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
printf("%lld\n", h[n]);
}
}