diverta2019-2 E - Balanced Piles
对于一个序列
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an,同时给它们分配一个
1
,
2
,
.
.
.
,
n
1,2,...,n
1,2,...,n的排列
b
1
,
b
2
,
.
.
,
b
n
b_1,b_2,..,b_n
b1,b2,..,bn,满足:
如果
a
i
<
a
j
(
i
≠
j
)
a_i<a_j(i\neq j)
ai<aj(i=j),则
b
i
<
b
j
b_i<b_j
bi<bj需满足。
b
b
b序列的性质:
a
i
a_i
ai相同的数的
b
b
b序列一定是连续的一段。如果
b
x
=
1
b_x=1
bx=1,则
a
x
a_x
ax一定是序列中的最小值。
序列
b
b
b用来表示序列
a
a
a中数的操作顺序。
如
a
=
[
1
,
3
,
2
,
2
,
3
,
1
]
,
b
=
[
2
,
6
,
3
,
4
,
5
,
1
]
a=[1,3,2,2,3,1],b=[2,6,3,4,5,1]
a=[1,3,2,2,3,1],b=[2,6,3,4,5,1]先操作第
6
6
6个位置,再第
1
1
1个位置、第
3
3
3个位置、第
4
4
4个位置、第
5
5
5个位置、第
2
2
2个位置。
当 a 1 = a 2 = . . . = a n = 0 a_1=a_2=...=a_n=0 a1=a2=...=an=0时,有 n ! n! n!种合法的排列 b b b。
随后修改一下问题:
初始有一个序列
a
1
=
a
2
=
.
.
.
=
a
n
=
0
a_1=a_2=...=a_n=0
a1=a2=...=an=0,首先需要给这个序列分配一个
1
,
2
,
.
.
.
,
n
1,2,...,n
1,2,...,n的排列
b
1
,
b
2
,
.
.
.
,
b
n
b_1,b_2,...,b_n
b1,b2,...,bn,然后执行下述操作若干次:
设序列中的最大值为
M
M
M,选择一个整数
x
∈
[
M
+
1
,
M
+
D
]
x\in [M+1,M+D]
x∈[M+1,M+D]。
- 如果 x ≠ H x\neq H x=H,则再选择若干个数 1 ≤ i 1 < i 2 < . . . < i t ≤ n 1\le i_1<i_2<...< i_t\le n 1≤i1<i2<...<it≤n满足 b i 1 , b i 2 , . . . , b i t b_{i_1},b_{i_2},...,b_{i_t} bi1,bi2,...,bit排序后的结果是 1 , 2 , . . . , t 1,2,...,t 1,2,...,t(确定了 t t t即可确定 1 ≤ i 1 < i 2 < . . . < i t ≤ n 1\le i_1<i_2<...< i_t\le n 1≤i1<i2<...<it≤n),随后令 a i 1 = a i 2 = . . . = a i t = x a_{i_1}=a_{i_2}=...=a_{i_t}=x ai1=ai2=...=ait=x,对于 j ∉ { i 1 , i 2 , . . . , i t } j\notin \{i_1,i_2,...,i_t\} j∈/{i1,i2,...,it},令 b j = b j − t b_j=b_j-t bj=bj−t,再给 b i 1 , b i 2 , . . . , b i t b_{i_1},b_{i_2},...,b_{i_t} bi1,bi2,...,bit分配一个 n − t + 1 , . . . , n − 1 , n n-t+1,...,n-1,n n−t+1,...,n−1,n的排列(有 t ! t! t!种可能的排列)。
- 如果 x = H x=H x=H,则令 a 1 = a 2 = . . . = a n = H a_1=a_2=...=a_n=H a1=a2=...=an=H且 b 1 = 1 , b 2 = 2 , . . . , b n = n b_1=1,b_2=2,...,b_n=n b1=1,b2=2,...,bn=n。
问有多少中不同的操作方案可以得到 a = [ H , H , . . . , H ] , b = [ 1 , 2 , . . . , n ] a=[H,H,...,H],b=[1,2,...,n] a=[H,H,...,H],b=[1,2,...,n]。
设
d
p
i
dp_i
dpi表示序列
a
a
a中最大值为
i
i
i时序列对
(
a
,
b
)
(a,b)
(a,b)的数量,有
d
p
0
=
n
!
d
p
i
=
∑
j
=
m
a
x
(
0
,
i
−
D
)
i
−
1
d
p
j
(
1
!
+
2
!
+
.
.
.
+
n
!
)
(
0
<
i
<
H
)
d
p
H
=
∑
j
=
m
a
x
(
0
,
H
−
D
)
H
−
1
d
p
j
dp_0=n!\\ dp_i=\sum_{j=max(0,i-D)}^{i-1} dp_j(1!+2!+...+n!)(0<i<H)\\ dp_H=\sum_{j=max(0,H-D)}^{H-1} dp_j
dp0=n!dpi=j=max(0,i−D)∑i−1dpj(1!+2!+...+n!)(0<i<H)dpH=j=max(0,H−D)∑H−1dpj
keyidea:在序列内决定好相同数的操作顺序,每次将最小值修改为 [ M , M + D ] [M,M+D] [M,M+D]中的某个数改成每次修改多个最小的数到 [ M + 1 , M + D ] [M+1,M+D] [M+1,M+D]中的某个数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// const int mod=998244353;
const int mod=1e9+7;
#define inf 0x3f3f3f3f
// #define inf 0x3f3f3f3f3f3f3f3fll
// #define DEBUG
inline void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);}
int main()
{
#ifdef DEBUG
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,h,d;
cin>>n>>h>>d;
vector<int>f(n+1);
f[0]=1;
for(int i=1;i<=n;++i) f[i]=1ll*f[i-1]*i%mod;
vector<int>dp(h+1);
int sum=0;
dp[0]=f[n];
for(int i=1;i<=n;++i) sum=(sum+f[i])%mod;
int s=dp[0];
for(int i=1;i<=h;++i)
{
if(i<h) dp[i]=1ll*s*sum%mod;
else dp[i]=s;
s=(s+dp[i])%mod;
if(i-d>=0) s=(s+mod-dp[i-d])%mod;
}
cout<<dp[h]<<'\n';
}