题目大意:
n < = 1 e 3 n<=1e3 n<=1e3
分析:
不考虑选择顺序,
设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示前
i
i
i个卡片,选了
j
j
j个卡片,第
i
i
i个卡片是否正面朝上(
1
是
0
否
1是0否
1是0否)的合法方案数。
假设到了第
i
i
i位,
填
1
1
1,
则上一位必定是
0
0
0,
f
i
,
j
,
1
+
=
f
i
−
1
,
j
−
1
,
0
f_{i,j,1}+=f_{i-1,j-1,0}
fi,j,1+=fi−1,j−1,0
填
0
0
0
则上一位必定是
1
1
1,
f
i
,
j
,
0
+
=
f
i
−
1
,
j
,
1
f_{i,j,0}+=f_{i-1,j,1}
fi,j,0+=fi−1,j,1
然后发现,
这样子对于特殊的
1001
1001
1001的形式中,对于
100
100
100是一个不合法的方案,
1001
1001
1001是一个合法的方案,即
1
1
1可以通过
+
(
00
)
+(00)
+(00)转移到下一个合法的
1
1
1,但是
10
10
10不能通过
+
(
0
)
+(0)
+(0)到
100
100
100
那么
f
i
,
j
,
1
+
=
f
i
−
3
,
j
−
1
,
1
f_{i,j,1}+=f_{i-3,j-1,1}
fi,j,1+=fi−3,j−1,1
注意单独处理
n
=
1
,
2
,
3
n=1,2,3
n=1,2,3时的
f
f
f即可推导完
然后考虑有选择顺序
其实就是多乘了一个阶乘
即
g
i
=
∑
j
=
0
i
j
∗
(
f
i
,
j
,
0
+
f
i
,
j
,
1
)
∗
j
!
∑
j
=
0
i
(
f
i
,
j
,
0
+
f
i
,
j
,
1
)
∗
j
!
g_i=\frac{\sum_{j=0}^{i}j*(f_{i,j,0}+f_{i,j,1})*j!}{\sum_{j=0}^{i}(f_{i,j,0}+f_{i,j,1})*j!}
gi=∑j=0i(fi,j,0+fi,j,1)∗j!∑j=0ij∗(fi,j,0+fi,j,1)∗j!
处理完
f
f
f直接算
g
g
g
对于每个询问
n
n
n直接回答
g
n
g_n
gn即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int mo = 1e9 + 7;
const int N = 1005;
typedef long long ll;
int n, t;
ll f[N][N][2], g[N], fac[N];
ll ksm(ll x, ll y) {
ll rp = 1;
for (; y; y >>= 1) {
if (y & 1) rp = rp * x % mo;
x = x * x % mo;
}
return rp;
}
int main() {
// freopen("data1.out", "w", stdout);
f[1][0][0] = 0; f[1][1][1] = 1;
f[2][1][0] = 1; f[2][1][1] = 1;
f[3][1][0] = 1, f[3][2][0] = 0; f[3][2][1] = 1;
for (int i = 4; i <= 1000; i++) {
for (int j = 1; j <= i; j++) {
(f[i][j][0] += f[i - 1][j][1]) %= mo; (f[i][j][0] += mo) %= mo;
(f[i][j][1] += f[i - 1][j - 1][0] + f[i - 3][j - 1][1]) %= mo; (f[i][j][1] += mo) %= mo;
}
}
fac[0] = 1; fac[1] = 1; for (int i = 2; i <= 1000; i++) fac[i] = 1ll*fac[i-1]*i%mo;
for (int i = 1; i <= 1000; i++) {
ll tot1 = 0, tot2 = 0, num = 0;
for (int j = 0; j <= i; j++) {
num = f[i][j][0] + f[i][j][1]; num %= mo;
tot1 += 1ll * j % mo * num % mo * fac[j] % mo, (tot1 += mo) %= mo,
tot2 += 1ll * num %mo* fac[j]% mo, (tot2 += mo) %= mo;
}
g[i] = tot1 * ksm(tot2, mo - 2) % mo;
(g[i] += mo) %= mo;
}
cin>>t;
while (t--) {
cin>>n; cout<<g[n]<<endl;
}
return 0;
}