题意:长度为
n
n
n,有
k
k
k 个逆序对的排列个数?
n
,
k
≤
1
e
5
n,k\le 1e5
n,k≤1e5
考虑新填一个数
i
i
i 进去,可能产生的贡献为
[
0
,
i
−
1
]
[0,i-1]
[0,i−1],于是问题等价于:
∑
i
=
1
n
a
i
=
k
,
a
i
∈
[
0
,
i
−
1
]
\sum_{i=1}^na_i=k,a_i\in[0,i-1]
∑i=1nai=k,ai∈[0,i−1] 的方案数
其实可以大力生成函数
F
(
x
)
=
1
(
1
+
x
)
(
1
+
x
+
x
2
)
.
.
.
(
1
+
x
+
x
2
+
.
.
.
+
x
n
)
F(x)=1(1+x)(1+x+x^2)...(1+x+x^2+...+x^n)
F(x)=1(1+x)(1+x+x2)...(1+x+x2+...+xn)
=
∏
i
=
1
n
(
1
−
x
i
)
(
1
−
x
)
n
=\frac{\prod_{i=1}^n(1-x^i)}{(1-x)^n}
=(1−x)n∏i=1n(1−xi)
=
(
∏
i
=
1
n
(
1
−
x
i
)
)
(
∑
j
=
0
n
(
j
+
n
−
1
j
)
x
j
)
=(\prod_{i=1}^n(1-x^i))(\sum_{j=0}^n\binom{j+n-1}{j}x^j)
=(i=1∏n(1−xi))(j=0∑n(jj+n−1)xj)
考虑枚举后面的,需要快速知道前面的第
i
∈
[
0
,
k
]
i\in[0,k]
i∈[0,k] 项
考虑其组合意义,就是选若干个不重复的数,和为
i
i
i,贡献为
(
−
1
)
个
数
(-1)^{个数}
(−1)个数
这里的个数显然是
k
\sqrt k
k 级别的,于是可以
d
p
dp
dp
f
i
,
j
f_{i,j}
fi,j 表示
i
i
i 个,和为
j
j
j 的方案,发现就是整体加若干个 1 填一个 1 再加整体加若干个 1
有一个坑点是当
j
>
n
j>n
j>n 时,可能有一个数被加成
n
+
1
n+1
n+1,强制填
n
+
1
n+1
n+1 容斥就可以了
复杂度
O
(
k
k
)
O(k\sqrt k)
O(kk)
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int M = 1000, N = 1e5 + 50;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans; }
int sgn(int a){ return (a&1)?Mod-1:1; }
void Add(int &a, int b){ a = add(a, b); }
int n, m, k, f[M][N];
int fac[N<<1], ifac[N<<1];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fac[n],mul(ifac[m],ifac[n-m])); }
void prework(int n){
fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
for(int i = 2; i <= n; i++) fac[i] = mul(fac[i-1], i);
ifac[n] = ksm(fac[n], Mod-2);
for(int i = n-1; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
}
int calc(int k){
int ans = 0;
for(int i = 0; i <= m; i++) Add(ans, mul(sgn(i),f[i][k]));
return ans;
}
int main(){
cin >> n >> k; prework(n + k + 5);
m = sqrt(k * 2) + 5; f[0][0] = 1;
for(int i = 1; i <= m; i++)
for(int j = i; j <= k; j++){
if(j >= i) f[i][j] = add(f[i][j-i], f[i-1][j-i]);
if(j > n) f[i][j] = dec(f[i][j], f[i-1][j-n-1]);
}
int ans = 0;
for(int i = 0; i <= k; i++){
Add(ans, mul(C(i+n-1,i),calc(k-i)));
} cout << ans; return 0;
}