LOJ #6077. 「2017 山东一轮集训 Day7」逆序对

链接: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 <bits/stdc++.h>
#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值