题目大意
给定
n,k
,请求出长度为
n
的逆序对数恰好为
答案对
109+7
取模。
1≤n,k≤105,1≤k≤(n2)
题目分析
首先问题可以转化成,你有
n
个变量
你要计算出使得
∑ni=1ai=k
成立的取值方案。
这个怎么计算呢?有下面两种方法,不过其实殊途同归。
容斥原理
考虑使用容斥,我们限制一些
ai≥i
。
设我们限制的
ai≥i
的
i
之和为
虽然总的方案有
2n
种,但是实际上,如果我限制的
ai
的
i
之和超过了
生成函数
题目实际上是求
我们可以枚举 j ,用组合数计算出相应的系数,然后计算前面的累乘里面相应的
累乘里面的式子是有组合意义的,与上面容斥原理推出来的一致。
计算方案数
于是现在的问题就变成了怎么计算在
1
至
脑补一下这样一个构造过程:一开始什么数都没有。对已有的数,我们有两种操作,一种是全部加
1
,一种是全部加
于是我们就可以写出这样的方程:设
注意到第一维我最多能够选择的数的个数显然是 O(k√) 级别的,因此时空复杂度是 O(kk√) 的。
于是本题就完美解决了。
代码实现
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int P=1000000007;
const int N=100050;
const int L=N<<1;
const int M=448;
int fact[L],invf[L];
int n,K,l,m,ans;
int f[M][N];
int quick_power(int x,int y)
{
int ret=1;
for (;y;y>>=1,x=1ll*x*x%P) if (y&1) ret=1ll*ret*x%P;
return ret;
}
void pre()
{
fact[0]=1;
for (int i=1;i<=l;++i) fact[i]=1ll*fact[i-1]*i%P;
invf[l]=quick_power(fact[l],P-2);
for (int i=l;i>=1;--i) invf[i-1]=1ll*invf[i]*i%P;
}
int C(int n,int m){return 1ll*fact[n]*invf[m]%P*invf[n-m]%P;}
void dp()
{
f[0][0]=1;
for (int i=1;i<=m;++i)
for (int j=0;j<=K;++j)
{
if (j>=i) f[i][j]=(f[i][j-i]+f[i-1][j-i])%P;
if (j>=n+1) f[i][j]=(f[i][j]-f[i-1][j-(n+1)]+P)%P;
}
}
void calc()
{
ans=0;
for (int i=0;i<=m;++i)
for (int k=0;k<=K;++k)
(ans+=(((i&1)?-1ll:1ll)*f[i][k]*C(K-k+n-1,n-1)%P+P)%P)%=P;
}
int main()
{
freopen("inverse.in","r",stdin),freopen("inverse.out","w",stdout);
scanf("%d%d",&n,&K),l=n+K,m=trunc(sqrt(K*2-1)),pre(),dp(),calc(),printf("%d\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}