calc
Description
一个序列a1,…,an是合法的,当且仅当:
长度为给定的n。
a1,…,an都是[1,A]中的整数。
a1,…,an互不相等。
一个序列的值定义为它里面所有数的乘积,即a1a2…an。
求所有不同合法序列的值的和。
两个序列不同当且仅当他们任意一位不一样。
输出答案对一个数mod取余的结果。
Input
一行3个数,A,n,mod。意义为上面所说的。
Output
一行结果。
Sample Input
9 7 10007
Sample Output
3611
HINT
数据规模和约定
0:A<=10,n<=10。
1..3:A<=1000,n<=20.
4..9:A<=10^9,n<=20
10..19:A<=10^9,n<=500。
全部:mod<=10^9,并且mod为素数,mod>A>n+1
蒟蒻完全不会伯努利数的做法,只会插值QWQ
思路:
考虑容斥,设
表示长度为
时的答案。
那么令
,有一个简单的容斥:
上式的含义是,枚举至少有多少个数相等,并容斥这种情况的贡献。
然后考虑
的求法。
显然这是个自然数幂和问题。
根据差分提供的信息,
是一个关于
的
次多项式。
因此预处理
,对于每个
进行一次
的拉格朗日插值即可~
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=509;
ll a,n,md;
ll fac[N],inv[N],f[N],s[N];
inline ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)ret=ret*a%md;
a=a*a%md;b>>=1;
}
return ret;
}
inline void init()
{
fac[0]=1;
for(int i=1;i<N;i++)
fac[i]=fac[i-1]*i%md;
inv[N-1]=qpow(fac[N-1],md-2);
for(int i=N-1;i>=1;i--)
inv[i-1]=inv[i]*i%md;
}
inline ll b(ll k)
{
static ll w[N],y[N],l,ans;
for(int i=1;i<=k+2 && i<=a;i++)
y[i]=qpow(i,k);
for(int i=2;i<=k+2 && i<=a;i++)
y[i]=(y[i]+y[i-1])%md;
if(a<=k+2)return y[a];
l=1;
for(int i=1;i<=k+2;i++)
l=l*(a-i)%md;
for(int i=1;i<=k+2;i++)
w[i]=(((k+2-i)&1?-1ll:1ll)*inv[i-1]*inv[k+2-i]%md+md)%md;
ans=0;
for(int i=1;i<=k+2;i++)
(ans+=w[i]*qpow(a-i,md-2)%md*y[i]%md)%=md;
return (ans*l%md+md)%md;
}
inline ll c(ll a,ll b)
{
return fac[a]*inv[b]%md*inv[a-b]%md;
}
int main()
{
scanf("%lld%lld%lld",&a,&n,&md);
init();
f[0]=1;
for(int i=1;i<=n;i++)
{
s[i]=b(i);
for(int j=1;j<=i;j++)
(f[i]+=(j&1?1:-1)*c(i-1,j-1)*s[j]%md*f[i-j]%md*fac[j-1]%md+md)%=md;
}
printf("%lld\n",f[n]);
return 0;
}