\(\frak{Description}\)

\(\rm Link.\)

\(\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)\),但我们又有 \(\binom{n}{k}\cdot k^{\underline i}=\binom{n-i}{k-i}\cdot n^{\underline i}\),所以原式

\[\sum_{k=0}^n\sum_{i=0}^m b_ik^\underline i\cdot x^k\cdot \binom{n}{k}=\sum_{k=0}^n\sum_{i=0}^m b_in^\underline i\cdot x^k\cdot \binom{n-i}{k-i} \]

此时 \(b_in^\underline i\) 已经是可接受的复杂度了,所以调换求和符号,尝试对组合数和 \(x^k\) 进行化简

\[\sum_{i=0}^mb_in^\underline i\cdot \sum_{k=0}^n x^k\cdot \binom{n-i}{k-i} \]

这有点像二项式定理(蛤?你确定),所以枚举 \(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\) 就将问题解决了。普通幂转下降幂多项式用第二类斯特林数,所以有

\[\begin{align} \sum_{i=0}^m a_ik^i&=\sum_{i=0}^m a_i\cdot \sum_{j=0}^i \text{S}(i,j)\cdot k^\underline j\\ &=\sum_{j=0}^m k^\underline j\cdot \sum_{i=j}^m \text{S}(i,j)\cdot a_i \end{align} \]

所以 \(\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;
}
posted on 2022-04-05 17:58  Oxide  阅读(33)  评论(0编辑  收藏  举报