###Description
求方程
∑
i
=
1
m
x
i
<
=
s
\sum_{i=1}^{m}xi<=s
∑i=1mxi<=s且对于i=1~n,
x
i
<
=
t
xi<=t
xi<=t的正整数解数。
n,m<=1e9,nt<=s<=1e18,m-n<=1e3
###Beat the Challeng
####Part 1
答案等于
∑
i
=
0
n
(
−
1
)
i
C
n
i
C
s
−
t
i
m
\sum_{i=0}^{n}(-1)^iC_n^iC_{s-ti}^m
i=0∑n(−1)iCniCs−tim
大概思路是容斥然后用组合数计算。
####Part 2
我们先来介绍一下n阶差分公式
定义一次差分
Δ
f
[
i
]
=
f
[
i
+
1
]
−
f
[
i
]
\Delta f[i]=f[i+1]-f[i]
Δf[i]=f[i+1]−f[i]
那么
Δ
n
f
\Delta^n f
Δnf为f经过n次差分之后所得的东西
一个结论:
Δ
n
f
[
x
]
=
∑
i
=
0
n
(
−
1
)
n
−
i
C
n
i
f
[
x
+
i
]
\Delta^n f[x]=\sum_{i=0}^{n}(-1)^{n-i}C_n^if[x+i]
Δnf[x]=∑i=0n(−1)n−iCnif[x+i]
证明的话可以归纳,暴力展开证明
那么我们设
A
n
s
=
(
−
1
)
n
a
n
s
Ans=(-1)^{n}ans
Ans=(−1)nans,
f
[
i
]
=
C
s
−
t
x
m
f[i]=C_{s-tx}^{m}
f[i]=Cs−txm
可以发现
A
n
s
=
∑
i
=
0
n
(
−
1
)
n
+
i
C
n
i
f
[
i
]
Ans=\sum_{i=0}^{n}(-1)^{n+i}C_n^if[i]
Ans=i=0∑n(−1)n+iCnif[i]
=
∑
i
=
0
n
(
−
1
)
n
−
i
C
n
i
f
[
i
]
=\sum_{i=0}^{n}(-1)^{n-i}C_n^if[i]
=i=0∑n(−1)n−iCnif[i]
=
Δ
n
f
[
0
]
=\Delta^n f[0]
=Δnf[0]
####Part 3
两类斯特林数及公式
第一类斯特林数
[
n
m
]
[_n^m]
[nm]表示将m个可区分元素划分成n个不可区分圆排列的方案数
也有公式
P
x
m
=
∑
i
=
0
m
(
−
1
)
m
−
i
[
i
m
]
x
i
P_x^m=\sum_{i=0}^{m}(-1)^{m-i}[_i^m]x^i
Pxm=i=0∑m(−1)m−i[im]xi
只是因为递推式相等罢了,因为不会打就用排列数代替下降幂了。。。
第二类斯特林数
{
n
m
}
{\{_n^m\}}
{nm}表示将m个可区分元素划分成n个不可区分的集合的方案数
也有公式
x
m
=
∑
i
=
0
m
{
i
m
}
P
x
i
x^m=\sum_{i=0}^{m}{\{_i^m\}}P_x^i
xm=i=0∑m{im}Pxi
考虑一个组合问题"将m个可区分的球扔到n个可区分的箱子里的方案数"
显然答案是
n
m
n^m
nm
再考虑枚举有球的箱子,假设有i个,那么我们需要将m个球划分成i个集合,然后对集合分配箱子。因为可区分所以是排列数。
####Part 4
回到原问题
f
[
x
]
=
C
s
−
t
x
m
f[x]=C_{s-tx}^m
f[x]=Cs−txm
=
1
m
!
P
s
−
t
x
m
={1\over m!}P_{s-tx}^{m}
=m!1Ps−txm
=
1
m
!
∑
i
=
0
m
(
−
1
)
m
−
i
[
i
m
]
(
s
−
t
x
)
i
={1\over m!}\sum_{i=0}^{m}(-1)^{m-i}[_i^m](s-tx)^i
=m!1i=0∑m(−1)m−i[im](s−tx)i
=
1
m
!
∑
i
=
0
m
(
−
1
)
m
−
i
[
i
m
]
∑
j
=
0
i
(
−
1
)
j
C
i
j
s
i
−
j
t
j
x
j
={1\over m!}\sum_{i=0}^{m}(-1)^{m-i}[_i^m]\sum_{j=0}^{i}(-1)^jC_i^js^{i-j}t^jx^j
=m!1i=0∑m(−1)m−i[im]j=0∑i(−1)jCijsi−jtjxj
=
1
m
!
∑
j
=
0
m
x
j
∑
i
=
j
m
(
−
1
)
m
−
i
+
j
[
i
m
]
C
i
j
S
i
−
j
t
j
={1\over m!}\sum_{j=0}^{m}x^j\sum_{i=j}^{m}(-1)^{m-i+j}[_i^m]C_i^jS^{i-j}t^j
=m!1j=0∑mxji=j∑m(−1)m−i+j[im]CijSi−jtj
设后面那个∑中的东西为a[j],那么
f
[
x
]
=
∑
i
=
0
m
x
i
a
[
i
]
f[x]=\sum_{i=0}^{m}x^ia[i]
f[x]=∑i=0mxia[i]
我们继续:
f
[
x
]
=
∑
i
=
0
m
x
i
a
[
i
]
f[x]=\sum_{i=0}^{m}x^ia[i]
f[x]=i=0∑mxia[i]
=
∑
i
=
0
m
a
[
i
]
∑
j
=
0
i
{
j
i
}
P
x
j
=\sum_{i=0}^{m}a[i]\sum_{j=0}^{i}\{_j^i\}P_x^j
=i=0∑ma[i]j=0∑i{ji}Pxj
=
∑
i
=
0
m
a
[
i
]
∑
j
=
0
i
{
j
i
}
C
x
j
j
!
=\sum_{i=0}^{m}a[i]\sum_{j=0}^{i}\{_j^i\}C_x^jj!
=i=0∑ma[i]j=0∑i{ji}Cxjj!
=
∑
j
=
0
m
C
x
j
∑
i
=
j
m
a
[
j
]
{
j
i
}
j
!
=\sum_{j=0}^{m}C_x^j\sum_{i=j}^{m}a[j]\{_j^i\}j!
=j=0∑mCxji=j∑ma[j]{ji}j!
令后面那个∑中的式子为b[j],那么我们有
f
[
x
]
=
∑
i
=
0
m
C
x
i
b
[
i
]
f[x]=\sum_{i=0}^{m}C_x^ib[i]
f[x]=∑i=0mCxib[i]
####Part 5
回到原始式子,我们有
A
n
s
=
Δ
n
f
[
0
]
Ans=\Delta^nf[0]
Ans=Δnf[0]
我们又得出了
f
[
x
]
=
∑
i
=
0
m
C
x
i
b
[
i
]
f[x]=\sum_{i=0}^{m}C_x^ib[i]
f[x]=∑i=0mCxib[i]
接下来我们给出一个结论:
如果
f
[
x
]
=
∑
i
=
0
m
C
x
i
g
[
i
]
f[x]=\sum_{i=0}^{m}C_x^ig[i]
f[x]=∑i=0mCxig[i]
那么
Δ
n
f
[
x
]
=
∑
i
=
0
m
g
[
i
]
C
x
i
−
n
\Delta^nf[x]=\sum_{i=0}^{m}g[i]C_x^{i-n}
Δnf[x]=∑i=0mg[i]Cxi−n
证明也可以暴力归纳。。。。
于是我们得出了
A
n
s
=
∑
i
=
0
m
b
[
i
]
C
0
i
−
n
Ans=\sum_{i=0}^{m}b[i]C_0^{i-n}
Ans=∑i=0mb[i]C0i−n
即
A
n
s
=
b
[
n
]
Ans=b[n]
Ans=b[n]
代回a和b我们可以得出
A
n
s
=
n
!
m
!
∑
i
=
n
m
{
n
i
}
∑
j
=
i
m
(
−
1
)
m
−
j
+
i
C
j
i
[
j
m
]
S
j
−
i
t
i
Ans={n!\over m!}\sum_{i=n}^{m}\{_n^i\}\sum_{j=i}^{m}(-1)^{m-j+i}C_j^i[_j^m]S^{j-i}t^i
Ans=m!n!i=n∑m{ni}j=i∑m(−1)m−j+iCji[jm]Sj−iti
由于i和j的差不超过m-n,所以如果我们知道了需要的两类斯特林数可以O((m-n)^2)计算
####Part 6
正常做法可能需要O(m^2),我们需要从组合意义上来理解。
因为将m个元素放入n个集合/圆排列中,我们都需要至少在每一个集合/排列中放一个数。
那么我们元素大于1个的集合/排列不会超过m-n个,可以设F[i][j]表示将i个元素插入j个元素>1的集合/排列的方案数,然后直接Dp。
最终计算时枚举到底有几个元素>1的集合/排列
这样总复杂度就是O((m-n)^2)的了,足以通过本题
zrO 提供此题的wzd Orz
然而外校有人考场切?!
###Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=2*1e3+5,Mo=1e9+7;
int pwr(int x,int y) {
int z=1;
for(;y;y>>=1,x=(ll)x*x%Mo)
if (y&1) z=(ll)z*x%Mo;
return z;
}
int n,m,mn,inv[N],ps[N];
int f[N][N],g[N][N],c[N][N],s[N],su[N];
ll S,T;
int C(int y,int x) {
if (x>2*mn) x=y-x;
return c[y-n][x];
}
int main() {
freopen("success.in","r",stdin);
freopen("success.out","w",stdout);
scanf("%lld%lld%d%d",&S,&T,&n,&m);
mn=m-n;S%=Mo;T%=Mo;
fo(i,0,2*mn) inv[i]=pwr(i,Mo-2);
ps[0]=1;fo(i,1,mn) ps[i]=(ll)ps[i-1]*S%Mo;
fo(i,0,2*mn) {
c[i][0]=1;
fo(j,1,min(i+n,2*mn)) {
c[i][j]=(ll)c[i][j-1]*(i+n-j+1)%Mo;
c[i][j]=(ll)c[i][j]*inv[j]%Mo;
}
}
f[0][0]=g[0][0]=1;
fo(i,1,2*mn)
fo(j,1,i/2) {
f[i][j]=(ll)f[i-1][j]*(i-1)%Mo;
g[i][j]=(ll)g[i-1][j]*j%Mo;
if (i>1) {
(f[i][j]+=(ll)f[i-2][j-1]*(i-1)%Mo)%=Mo;
(g[i][j]+=(ll)g[i-2][j-1]*(i-1)%Mo)%=Mo;
}
}
fo(i,0,mn)
fo(j,0,min(m-(i+n),i+n))
(su[i]+=(ll)f[m-(i+n)+j][j]*C(m,m-(i+n)+j)%Mo)%=Mo;
fo(i,0,mn)
fo(j,0,min(i,n))
(s[i]+=(ll)g[i+j][j]*C(n+i,i+j)%Mo)%=Mo;
int ans=0;
fo(i,0,mn) {
int sum=0,pt=pwr(T,i+n);
fo(j,i,mn) {
int res=(ll)C(n+j,n+i)*su[j]%Mo*ps[j-i]%Mo*pt%Mo;
if ((m-j+i)&1) (sum+=Mo-res)%=Mo;
else (sum+=res)%=Mo;
}
(ans+=(ll)sum*s[i]%Mo)%=Mo;
}
fo(i,n+1,m) ans=(ll)ans*pwr(i,Mo-2)%Mo;
if (n&1) ans=Mo-ans;
printf("%d\n",ans);
return 0;
}
UPD(2019.1.1)
然而这道题被林立打爆了。。。。
考虑原式子的组合意义,相当于有n+1组,前n组有t个,最后一组有s-nt个,从中选出m个数,前n组至少选一个的方案数
生成函数为
[
x
m
]
(
(
x
+
1
)
t
−
1
)
n
(
x
+
1
)
s
−
n
t
[x^m]((x+1)^t-1)^n(x+1)^{s-nt}
[xm]((x+1)t−1)n(x+1)s−nt
考虑写成
[
x
m
−
n
]
(
(
x
+
1
)
t
−
1
x
)
n
(
x
+
1
)
s
−
n
t
[x^{m-n}]({(x+1)^t-1\over x})^n(x+1)^{s-nt}
[xm−n](x(x+1)t−1)n(x+1)s−nt
就只用保留前m-n项,直接暴力就好了
还可以用多项式取模做到O((m-n) log m-n log n)