求 ∑mi=1immi 。
目前想到的做法是 m2logn 的,不知道可不可以分治什么的继续简化复杂度。
这个式子里比较难处理的是 im 这一项,于是尝试用做差法消掉点什么。
m∑mi=1immi−∑mi=1immi
=∑n+1i=2(i−1)mmi−∑ni=1immi
=∑ni=1((i−1)m−im)mi+nmmn+1
似乎是一大坨乱的东西,但是如果用二项式定理把m次幂给拆了之后会发现很好玩的东西。
=nmmn+1−∑ni=1(im−(i−1)m)
=nmmn+1−∑ni=1∑m−1j=0(−1)j(mj)ijmi
出现了 ijmi !
令 Sk=∑ni=1ikmi ,换一下上面的 ∑ 。
=nmmn+1−∑m−1j=0(−1)m−j(mj)∑ni=1ijmi
=nmmn+1−∑m−1j=0(−1)m−j(mj)Sj
于是可以有通项
Sk=nkmn+1−∑k−1j=0(−1)k−j(kj)Sjm−1
推了两节课。。。呼。。。。
预处理阶乘和逆元然后递推。
时间复杂度 O(m2logn) 。
#include
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define maxn 1007
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
typedef long long ll ;
typedef ll arr[maxn];
const ll mod = 1000000007;
inline ll add(ll a , ll b) { return ((ll) a + b) % mod ; }
inline ll mul(ll a , ll b) { return ((ll) a * b) % mod ; }
inline ll dec(ll a , ll b) { return ((((ll) a - b) % mod) + mod) % mod ; }
inline ll Pow(ll a , ll b) {
ll t = 1;
while (b) {
if (b & 1) t = mul(t , a);
a = mul(a , a) , b >>= 1;
}
return t;
}
arr PowN , fact , invF , S;
ll n , m;
void input() {
n = rd() , m = rd();
PowN[0] = 1;
rep (i , 1 , m) PowN[i] = mul(PowN[i - 1] , n);
fact[0] = 1;
rep (i , 1 , m) fact[i] = mul(fact[i - 1] , i);
invF[0] = 1;
rep (i , 1 , m) invF[i] = mul(invF[i - 1] , Pow(i , mod - 2));
}
inline ll _C(ll n , ll m) {
if (n < m) return 0;
return mul(fact[n] , mul(invF[n - m] , invF[m]));
}
void solve() {
if (m == 1) {
printf("%lld\n" , (ll) (n * (n + 1) / 2) % mod);
return;
}
ll M = Pow(m , n + 1),
_M = Pow(m - 1 , mod - 2);
S[0] = mul(dec(M , m) , _M);
rep (i , 1 , m) {
S[i] = mul(PowN[i] , M);
rep (j , 0 , i - 1)
S[i] = dec(S[i] , mul(_C(i , j) , S[j]) * (((i - j) & 1) ? 1 : -1));
S[i] = mul(S[i] , _M);
}
printf("%lld\n" , S[m]);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
freopen("data.out" , "w" , stdout);
#endif
input();
solve();
return 0;
}