题目大意
% 给定 [1,A][1,A][1,A] 之间的数,从其中取出 mmm 个数排列,每种方案的价值为序列中所有元素的乘积,求所有方案的价值和在 modmodmod 意义下的值。
数据范围 1⩽A⩽109,n⩽500,mod∈prime,mod⩽109,mod>A>n+11\leqslant A\leqslant 10^9,n\leqslant 500,mod\in \text{prime},mod\leqslant 10^9,mod>A>n+11⩽A⩽109,n⩽500,mod∈prime,mod⩽109,mod>A>n+1
题解
% 先考虑动态规划,直接问什么定义什么似乎很难转移。那就只能分析题目了。首先,我们发现方案的价值和顺序无关,因而我们可以求出严格上升序列的价值,然后乘上排列方案数 n!n!n! 。
定义:用 1∼j1\sim j1∼j 填满序列的前 iii 个位置,能得到的严格上升序列的总价值为 f[i][j]f[i][j]f[i][j]。
那么转移就很好写了:f[i][j]=f[i−1][j−1]×j+f[i][j−1]f[i][j]=f[i-1][j-1]\times j+f[i][j-1]f[i][j]=f[i−1][j−1]×j+f[i][j−1] 则答案为 f[n][A]×n!f[n][A]\times n!f[n][A]×n!,时间复杂度为 Θ(n×A)\Theta(n\times A)Θ(n×A),对于本题来说显然是错的。
考虑优化,如果我们知道 f[n][A]f[n][A]f[n][A] 的次数,那就可以套拉格朗日插值了。
尝试令 f[i][j]f[i][j]f[i][j] 是一个关于 iii 的 g(n)g(n)g(n) 次多项式。我们知道,一个 iii 次多项式差分后为一个 i−1i-1i−1 次多项式,因而有:f[i][j]−f[i−1][j]f[i][j]-f[i-1][j]f[i][j]−f[i−1][j] 为一个 g(i)−1g(i)-1g(i)−1 次多项式。对方程式移项,得f[i][j]−f[i][j−1]=f[i−1][j−1]×jf[i][j]-f[i][j-1]=f[i-1][j-1]\times jf[i][j]−f[i][j−1]=f[i−1][j−1]×j 等式左侧为 g(i)−1g(i)-1g(i)−1 次多项式,右侧为 g(n−1)+1g(n-1)+1g(n−1)+1 次多项式,因而有:
g(n)−1=g(n−1)+1g(n)-1=g(n-1)+1g(n)−1=g(n−1)+1 化简,得:g(n)=g(n−1)+2g(n)=g(n-1)+2g(n)=g(n−1)+2 可以用断言并用生成函数证明:g(n)=2ng(n)=2ng(n)=2n 因而原方程为一个 2n2n2n 次的多项式。我们先计算出 f(n,1)∼f[n][2n+1]f(n,1)\sim f[n][2n+1]f(n,1)∼f[n][2n+1],时间复杂度为 Θ(n)\Theta(n)Θ(n)。然后用拉格朗日插值求出 f[n][A]f[n][A]f[n][A],总时间复杂度为 T(n)=Θ(n2)T(n)=\Theta(n^2)T(n)=Θ(n2)
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 510
long long A,n;
long long mod;
long long f[maxn][maxn*2];
long long x[maxn],y[maxn];
long long pow_t(long long a,long long b){
if(b==1) return a%mod;
long long t=pow_t(a,b>>1);
if((b&1)==0) return t*t%mod;
return t*t%mod*a%mod;
}
#define inv(x) pow_t(x,mod-2)
long long ft(long long n,long long k){
long long ans=0;
for(int i=0;i<n;i++){
long long up=y[i]%mod,dn=1;
for(int j=0;j<n;j++)
if(i!=j)
up=up*(k-x[j]+mod)%mod,dn=dn*(x[i]-x[j]+mod)%mod;
ans=(ans+up*inv(dn)%mod)%mod;
} return ans;
}
int main(void)
{
scanf("%lld%lld%lld",&A,&n,&mod);
long long fac_n=1;
for(int i=1;i<=n;i++)
fac_n=fac_n*i%mod;
for(int i=0;i<=2*n+1;i++)
f[0][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=2*n+1;j++)
f[i][j]=(f[i-1][j-1]*j%mod+f[i][j-1])%mod;
for(int i=1;i<=2*n+1;i++)
x[i-1]=i,y[i-1]=f[n][i];
printf("%lld",fac_n*ft(2*n+1,A)%mod);
return 0;
}