bzoj3157&&3516国王奇遇记(dp)

本文介绍了一种利用O(m^2)DP算法解决特定数学问题的方法,通过推导公式并使用扰乱法简化计算过程,实现了高效递推。特别讨论了当m等于1的情况,并提供了完整的代码实现。

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

传送门
传送门
随便推一波式子然后O(m^2)dp即可
f ( i ) = ∑ k = 1 n k i m k f(i)=\sum_{k=1}^nk^im^k f(i)=k=1nkimk
然后用扰乱法化简:
( m − 1 ) f ( i ) = ∑ k = 1 n k i m k + 1 − ∑ k = 1 n k i m k (m-1)f(i)=\sum_{k=1}^nk^im^{k+1}-\sum_{k=1}^nk^im^k (m1)f(i)=k=1nkimk+1k=1nkimk
最后化简出来可以 O ( m 2 ) O(m^2) O(m2)递推
注意特判 m = 1 m=1 m=1的情况。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int mod=1e9+7;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int&a,const int&b){a=a>=b?a-b:a-b+mod;}
inline void Mul(int&a,const int&b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,a=mul(a,a))if(p&1)Mul(ret,a);return ret;}
const int N=1005;
int n,m,f[N],inv[N],fac[N],ifac[N],d;
inline void init(){
    inv[1]=ifac[0]=ifac[1]=fac[0]=fac[1]=1;
    for(ri i=2;i<=m;++i)fac[i]=mul(fac[i-1],i);
    for(ri i=2;i<=m;++i)inv[i]=mul(inv[mod-mod/i*i],mod-mod/i),ifac[i]=mul(ifac[i-1],inv[i]);
}
inline int C(int n,int m){return mul(fac[n],mul(ifac[m],ifac[n-m]));}
int main(){
    cin>>n>>m;
    if(m==1)return cout<<(ll)n*(n+1)/2%mod,0;
    init();
    f[0]=mul(dec(d=ksm(m,n+1),m),inv[m-1]);
    for(ri t,w=n,i=1;i<=m;++i,Mul(w,n)){
        f[i]=mul(w,d);
        for(ri j=0,ff=i&1;j<i;++j,ff^=1)t=mul(f[j],C(i,j)),ff?Dec(f[i],t):Add(f[i],t);
        Mul(f[i],inv[m-1]);
    }
    cout<<f[m];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值