题目要求
[sum_{k=0}^nf(k) imes x^k imesdbinom{n}{k}
]
我觉得 ix35 的方法还是蛮不错的,其他的斯特林数推导和组合意义 dp 都给我看傻了
首先考虑将 (f) 拆成单项式有
[sum_{i=0}^ma_i imes k^i imes dbinom{n}{k}
]
由 (k imes dbinom{n}{k}=n imes dbinom{n-1}{k-1}) 向外扩展
把 (k^2 imes dbinom{n}{k},k^3 imesdbinom{n}{k}dots) 手算一遍
可以发现对于 (k^p imes dbinom{n}{k}) 有一般形式
[=sum_{i=1}^pS(p,j) imes n^{underline{j}} imesdbinom{n-j}{k-j}
]
并且对于 (S(p,j)=S(i-1,j) imes j+S(i-1,j-1)) 存在这个递归式
这个时候回带到原式中
[sum_{k=0}^{n}x^kleft(a_0+sum_{i=1}^ma_i imes k^i imes dbinom{n}{k}
ight)
]
务必要特殊讨论 (a_0) 的存在,否则你会因为这个死活过不去大样例。
把关于 n 的求和符号换进去,可以得到这样一个式子
[sum_{k=0}^nx^ksum_{j=1}^i
S(i,j) imes n^{underline{j}} imesdbinom{n-j}{k-j}
]
进一步交换
[sum_{j=1}^i
S(i,j) imes n^{underline{j}} imessum_{k=0}^nx^kdbinom{n-j}{k-j}
]
单独考虑后面那个求和符号,等价于
[x^jsum_{k=0}^{n-j}xdbinom{n-j}{k}
]
再用一步二项式定理(一定要带着那个 (x^j),不然还是只能过第一个样例
[x^j imes(1+x)^{n-j}
]
整理一下
[a_0(1+x)^n+sum_{i=1}^ma_ileft(sum_{j=1}^iS(i,j) imes n^{underline{j}} imes x^j imes(1+x)^{n-j}
ight)
]
然后这个一个依赖 (n) 的算法被我们改造成了依赖 (m) 的算法,复杂度是 (O(m^2log m))
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
template<typename _T>
inline void read(_T &x)
{
x=0;char s=getchar();int f=1;
while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
x*=f;
}
const int np = 1e3 + 5;
int a[np];
int x,n,m,p;
int s[np][np];
int dfac[np];
int x_[np];
inline int power(int a,int b)
{
int res(1);
while(b)
{
if(b & 1) res = res * a,res %= p;
a = a * a ;
a %= p;
b >>= 1;
}
return res;
}
signed main()
{
read(n),read(x),read(p),read(m);
for(int i=0;i <=m;i++) read(a[i]);
for(int i=1;i <= 1000;i ++)
{
s[i][1] = 1;
for(int j=2;j <= i;j++)
{
s[i][j] = s[i-1][j]*j+s[i-1][j-1];
s[i][j] %= p;
}
// for(int j=1;j<=i;j++) printf("%lld ",s[i][j]);
// printf("
");
}
dfac[0] =1 ;
for(int i=1;i <= 1000;i ++)
{
dfac[i] = dfac[i-1]*(n-i+1);
dfac[i] %= p;
}
int Ans =power(1+x,n)*a[0];
Ans %= p;
for(int i=1;i <= m;i ++)
{
int qAns = 0;
for(int j=1;j <= i;j ++)
{
qAns += ((((s[i][j] * dfac[j])%p) * power(x,j)%p) *power(1 + x,n-j))%p;
qAns %= p;
}
qAns *= a[i];
qAns %= p;
Ans += qAns;
Ans %= p;
// printf("%lld
",Ans);
}
// Ans += ((n+1) * n* a[0])%p;
// Ans %= p;
printf("%lld",Ans);
}
以后遇到这样的数学推导题,经过一遍草率的推导得到了最终式子的时候,一定要从头认真推导一遍,每一个项都不能忽略