題目大意
給定
答案對
題目分析
首先問題可以轉化成,你有
你要計算出使得
這個怎麼計算呢?有下面兩種方法,不過其實殊途同歸。
容斥原理
考慮使用容斥,我們限制一些
設我們限制的
雖然總的方案有
生成函數
題目實際上是求
我們可以枚舉
累乘裏面的式子是有組合意義的,與上面容斥原理推出來的一致。
計算方案數
於是現在的問題就變成了怎麼計算在
腦補一下這樣一個構造過程:一開始什麼數都沒有。對已有的數,我們有兩種操作,一種是全部加
於是我們就可以寫出這樣的方程:設
注意到第一維我最多能夠選擇的數的個數顯然是
於是本題就完美解決了。
代碼實現
#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;
}