1. 程式人生 > 其它 >1、手撕Promise上

1、手撕Promise上

\(\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;
}