某考试 T1 table
我们把每一行看成一个多项式 f[i][1] + f[i][2] * x + f[i][3] * x^2 + ..... + f[i][n] * x^(n-1) 的话,一行转移到下一行就相当于乘上一个{b*x + a}的多项式。
于是本题就有了不下五种做法233333,但是大部分做法都因为用了多次NTT而被卡常,就算只用了一次NTT的算法过了,那也不是最优的,因为我们完全可以把 (b*x + a)^n 广义二项式展开,这样就可以 O(N) 计算出转移多项式 (因为n<0也适用广义多项式定理,所以多项式求逆干嘛)。
而且因为询问只问一个点的值,所以我们直接暴力卷积算出这个点的值就行了,根本不用写NTT把这一行都算出来(别拦我我要去跳楼)。然后考场我就是因为把这一行都算出来了...导致复杂度在O(NK)上多了一个log
好不容易想到广义二项式展开了最后还是只有40分qwq。。。。。
/* (bx + a)^n 广义二项式定理展开 (bx)^k * a^(n-k) * n^k_ * (1/k!) x=0 : a^n * n^0_ * (1/0!) x=1 : (bx)^1 * a^(n-1) * n^1_ * (1/1!) */ #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<ctime> #include<cstring> #define ll long long using namespace std; const int maxn=100000; const int ha=998244353; int o[maxn+5],ni[maxn+5]; int n,m,A,B,P,Q,jc[maxn+5]; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline void init(){ jc[0]=1; for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha; ni[maxn]=ksm(jc[maxn],ha-2); for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha; } inline int get(int x,int y){ if(!x) return o[y]; int C=(x>0?ksm(A,x):ksm(ksm(A,-x),ha-2)),invA=ksm(A,ha-2); int ans=0,S=1,now=add(x,ha); for(int i=0;i<=y;S=S*(ll)now%ha,now=add(now,ha-1),i++){ ans=add(ans,S*(ll)ni[i]%ha*(ll)C%ha*(ll)o[y-i]%ha); C=C*(ll)B%ha*(ll)invA%ha; } return ans; } inline void solve(){ for(int i=0;i<n;i++) scanf("%d",o+i); while(Q--){ int row,line; scanf("%d%d",&row,&line),line--; printf("%d\n",get(row-P,line)); } } int main(){ // freopen("table.in","r",stdin); // freopen("table.out","w",stdout); init(); scanf("%d%d%d%d%d%d",&m,&n,&A,&B,&P,&Q); solve(); return 0; }
我爱学习,学习使我快乐