1、手撕Promise上
阿新 • • 發佈:2022-03-30
\(\frak{Description}\)
\(\frak{Solution}\)
當時拿到這道題的第一想法就是將多項式 \(f(k)\) 拆成單項式,然後就死了。(但是題解區有巨佬用單項式和純組合數學搞出來了,我是 \(\rm joker\).
將 \(f(k)=\sum_{i=0}^m a_ik^i\) 轉化成 \(f(k)=\sum_{i=0}^m b_ik^\underline i\). 但是你要問我怎麼想到普通冪轉下降冪多項式,我真的不能解釋,可能需要多做題吧。由於 \(k^i\) 和 \(\binom{n}{k}\) 之間沒有什麼公式,列舉複雜度直接 \(\mathcal O(nm)\)
此時 \(b_in^\underline i\) 已經是可接受的複雜度了,所以調換求和符號,嘗試對組合數和 \(x^k\) 進行化簡
這有點像二項式定理(蛤?你確定),所以列舉 \(k-i\)
\[\sum_{i=0}^mb_in^\underline i\cdot \sum_{k=0}^{n-i} x^{k+i}\cdot \binom{n-i}{k}=\sum_{i=0}^mb_in^\underline ix^i\cdot \sum_{k=0}^{n-i} x^{k}\cdot \binom{n-i}{k} \]所以
\[\text{Ans}=\sum_{i=0}^mb_in^\underline ix^i\cdot (x+1)^{n-i} \]現在只要求出 \(b_i\)
所以 \(\mathcal O(m^2)\) 預處理第二類斯特林數,再 \(\mathcal O(m^2)\) 遞推即可得知 \(b_i\).
\(\frak{Code}\)
# include <cctype>
# include <cstdio>
# define print(x,y) write(x), putchar(y)
template <class T>
inline T read(const T sample) {
T x=0; char s; bool f=0;
while(!isdigit(s=getchar())) f|=(s=='-');
for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
return f? -x: x;
}
template <class T>
inline void write(T x) {
static int writ[50], w_tp=0;
if(x<0) putchar('-'), x=-x;
do writ[++w_tp]=x-x/10*10, x/=10; while(x);
while(putchar(writ[w_tp--]^48), w_tp);
}
const int maxn = 1005;
int S[maxn][maxn];
int n,x,p,m,a[maxn],b[maxn];
inline int qkpow(int x,int y) {
int r=1;
for(; y; y>>=1, x=1ll*x*x%p)
if(y&1) r=1ll*r*x%p;
return r;
}
int main() {
n=read(9), x=read(9), p=read(9), m=read(9);
for(int i=0;i<=m;++i) a[i]=read(9);
S[0][0]=1;
for(int i=1;i<=m;++i)
for(int j=1;j<=i;++j)
S[i][j] = (S[i-1][j-1]+1ll*j*S[i-1][j]%p)%p;
for(int j=0;j<=m;++j) for(int i=j;i<=m;++i)
b[j] = (b[j]+1ll*S[i][j]*a[i]%p)%p;
int ans=0, tmp=1, tmpx=1;
for(int i=0;i<=m;++i)
ans = (ans+1ll*b[i]*tmp%p*tmpx%p*qkpow(x+1,n-i)%p)%p,
tmp = 1ll*tmp*(n-i)%p, tmpx = 1ll*tmpx*x%p;
print(ans,'\n');
return 0;
}