链接:https://loj.ac/problem/6077
题解:DP
首先注意到如果从小到大填进去第i个数,那么逆序对会增加[0, i - 1]个
问题转化为:∑x[i] = k, 0 <= x[i] < i,问解数
这是个经典问题,我们考虑容斥,至少有j个不满足条件,剩下随便选
不满足条件即x[i] >= i,我们把k减去i,然后就是个组合数的事情了
我们需要求出f(i, j)表示[1, n]中i个数,和为j的方案数(带上容斥系数)
考虑如何统计,假设我们得到了一个序列,我们可以将它+1,并且可以选择是否在最后添加一个1
这样可能会出现某个数为n + 1,我们减掉就好了
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fill(x, y) memset(x, y, sizeof x)
#define copy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair < int, int > pa;
inline int read()
{
int sc = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') sc = sc * 10 + ch - '0', ch = getchar();
return sc * f;
}
const int MAXN = 200005;
const int MAXM = 450;
const int mod = 1e9 + 7;
int f[MAXM][MAXN], n, m, fac[MAXN], inv[MAXN], ans;
inline int qpow(int x, int y) { int ret = 1; for (; y ; y >>= 1, x = 1LL * x * x % mod) if (y & 1) ret = 1LL * ret * x % mod; return ret; }
inline int C(int x, int y) { return 1LL * fac[x] * inv[y] % mod * inv[x - y] % mod; }
inline void inc(int &x, int y) { x += y; if (x >= mod) x -= mod; }
inline void dec(int &x, int y) { x -= y; if (x < 0) x += mod; }
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = read(), m = read();
fac[0] = inv[0] = 1;
for (int i = 1; i <= n + m; i ++)
fac[i] = 1LL * fac[i - 1] * i % mod;
inv[n + m] = qpow(fac[n + m], mod - 2);
for (int i = n + m - 1; i; i --)
inv[i] = 1LL * inv[i + 1] * (i + 1) % mod;
f[0][0] = 1;
for (int i = 1; i < MAXM; i ++)
for (int j = 0; j <= m; j ++)
{
if (j >= i)
dec(f[i][j], f[i - 1][j - i]), inc(f[i][j], f[i][j - i]);
if (j >= n + 1)
inc(f[i][j], f[i - 1][j - (n + 1)]);
}
for (int i = 0, t = 0; i <= m; inc(ans, 1LL * t * C(n + m - i - 1, n - 1) % mod), t = 0, i ++)
for (int j = 0; j < MAXM; j ++)
inc(t, f[j][i]);
return printf("%d\n", ans), 0;
}