【bzoj3157】 【bzoj3516】 国王奇遇记 && 国王奇遇记加强版

本文介绍了一种求解∑mi=1immi的数学问题的方法,通过差分技巧和二项式定理,推导出了一个可以在预处理阶乘和逆元的情况下以O(m^2logn)的时间复杂度进行递推的公式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  求mi=1immi
  目前想到的做法是m2logn的,不知道可不可以分治什么的继续简化复杂度。
  这个式子里比较难处理的是im这一项,于是尝试用做差法消掉点什么。
      mmi=1immimi=1immi
  =n+1i=2(i1)mmini=1immi
  =ni=1((i1)mim)mi+nmmn+1
  似乎是一大坨乱的东西,但是如果用二项式定理把m次幂给拆了之后会发现很好玩的东西。
  =nmmn+1ni=1(im(i1)m)
  =nmmn+1ni=1m1j=0(1)j(mj)ijmi
  出现了ijmi
  令Sk=ni=1ikmi,换一下上面的
  =nmmn+1m1j=0(1)mj(mj)ni=1ijmi
  =nmmn+1m1j=0(1)mj(mj)Sj
  于是可以有通项
  Sk=nkmn+1k1j=0(1)kj(kj)Sjm1
  推了两节课。。。呼。。。。
  预处理阶乘和逆元然后递推。
  时间复杂度O(m2logn)
  

#include <bits/stdc++.h>
#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值