bzoj 3157 & bzoj 3516 国王奇遇记 —— 推式子

时间:2024-09-01 19:05:38

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3157

https://www.lydsy.com/JudgeOnline/problem.php?id=3516

这篇博客写得太好:http://blog.miskcoo.com/2014/06/bzoj-3157

然而目前之会 \( O(m) \) 的做法;

感觉关键是设计 \( S_{i} \),把它设在 \( m \) 那一维上很妙,毕竟 \( i^{m} \) 不太好做;

然而推式子都是针对 \( m != 1 \) 的,仔细一看 \( m = 1 \) 时就是 \( \sum\limits_{i=1}^{n} i \),注意特判。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=,mod=1e9+;
int n,m,s[xn],c[xn][xn];
ll pw(ll a,int b)
{
ll ret=; a=a%mod;
for(;b;b>>=,a=(a*a)%mod)if(b&)ret=(ret*a)%mod;
return ret;
}
int upt(int x){while(x>=mod)x-=mod; while(x<)x+=mod; return x;}
void init()
{
for(int i=;i<=m;i++)c[i][]=;
for(int i=;i<=m;i++)
for(int j=;j<=m;j++)
c[i][j]=upt(c[i-][j]+c[i-][j-]);
}
int main()
{
scanf("%d%d",&n,&m); init();
if(m==){printf("%lld\n",(ll)n*(n+)%mod*pw(,mod-)%mod); return ;}
else s[]=upt((ll)m*(-pw(m,n))%mod*pw(-m,mod-)%mod);
for(int k=;k<=m;k++)
{
s[k]=(ll)pw(n,k)*pw(m,n+)%mod;
for(int j=;j<k;j++)
s[k]=upt(s[k]+(ll)((k-j)%?-:)*c[k][j]*s[j]%mod);
s[k]=(ll)s[k]*pw(m-,mod-)%mod;//!
}
printf("%d\n",s[m]);
return ;
}