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

  求 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 
#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;
}

你可能感兴趣的:(组合数学,递推)