题解:AT_abc208_f [ABC208F] Cumulative Sum
观察样例解释题。
我们把样例解释搬过来看看。
我们观察到这个函数有一个非常重要的东西:
所以,我们很自然地改写这个表格为:
我们发现每个
更加本质地,回想一下我们在提高组学的一个经典问题:
从
(0,0) 走到(n,m) ,每次只能向上或向右走一个单位,有多少种路径?
我们知道这个答案的封闭形式实际就是
也就是说,每一个数最终出现的次数,实际是一个路径计数的结果。
那么我们稍微推一下就会发现,数
那么最终的结果就是
无论如何,这个东西都是不好直接计算的。
于是我们引入多项式。
由于
具体地:
这实际上是一个关于
为什么?
有一个基本事实是:若
换句话说,如果
对多项式暴力展开即可,读者自证不难。
由于
而我们知道
而且我们还知道
由
那么我们只要求出
:::success[AC code]
#include<bits/stdc++.h>
using namespace std;
constexpr int N = 2.5e6+32,M = 31,mod = 1e9+7;
long long n;
int m,k,f[N],y[N],fact[N],inv[N],pre[N];
inline int qpow(int base,int e){
int res = 1;
while(e){
if(e&1){
res = 1ll*res*base%mod;
}
base = 1ll*base*base%mod;
e>>=1;
}
return res;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n >> m >> k;
for(int i = 1;i<=m+k;++i){
f[i] = qpow(i,k);
}
for(int i = 1;i<=m;++i){
for(int j = 1;j<=m+k;++j){
f[j] = (f[j]+f[j-1])%mod;
}
}
for(int i = 1;i<=m+k;++i){
y[i] = f[i];
}
fact[0] = 1;
for(int i = 1;i<=m+k;++i){
fact[i] = 1ll*fact[i-1]*i%mod;
}
inv[m+k] = qpow(fact[m+k],mod-2);
for(int i = m+k-1;i>=0;--i){
inv[i] = 1ll*inv[i+1]*(i+1)%mod;
}
n%=mod;
if(n<=m+k){
cout << y[n];
return 0;
}
pre[0] = 1;
for(int i = 0;i<=m+k;++i){
pre[i+1] = 1ll*pre[i]*((n-i+mod)%mod)%mod;
}
int ans = 0,suf = 1;
for(int i = m+k;i>=0;--i){
int num = 1ll*pre[i]*suf%mod;
int term = 1ll*y[i]*num%mod;
term = 1ll*term*inv[i]%mod*inv[m+k-i]%mod;
if((m+k-i)&1){
ans = (ans-term+mod)%mod;
}else{
ans = (ans+term)%mod;
}
suf = 1ll*suf*((n-i+mod)%mod)%mod;
}
cout << ans;
return 0;
}
:::