BZOJ4944: [Noi2017]泳池(線性遞推)
阿新 • • 發佈:2019-01-25
題解:
首先轉換問題為最終面積小等於的個數。
注意到最終圖形的底邊會被禁止的地方分為不同段,每一段的最大面積都不能超過,那麼我們記為底邊長度為且他的上方的圖形最大面積不超過的概率,然後就是線性遞推了。
考慮如何處理,這一段底邊一定會向上延伸至某個地方被卡住,然後這個位置相當於把這個圖形切為兩半,滿足兩邊的高度大於位置的高度,面積小等於,我們增加一維表示長度為的底邊,高為之後會被卡住,最大面積小等於的概率,然後就會發現兩邊的矩形是一個子問題。 所以我們可以列舉哪個地方被卡住來DP。適當運用字首和技巧可以優化至 (或者多項式求逆優化至)。
注意有一個小細節是一行有多個被卡住的地方,此時要求左邊高度嚴格大於,右邊高度不嚴格大於即可。
線性遞推用特徵多項式優化,時間複雜度為。
#include <bits/stdc++.h>
using namespace std;
inline int rd(int x=0) {return (scanf("%d",&x),x);}
const int K=2e3+50,mod=998244353;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (unsigned long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
int n,q,pw[K],deg;
int g[K][K],s[K],A[K],B[K],C[K],f[K];
inline void mul(int *a,int *b,int *c) {
static int tp[K], tp2[K];
memcpy(tp,a,sizeof(int)*deg);
memcpy(tp2,b,sizeof(int)*deg);
memset(c,0,sizeof(int)*deg);
for(int i=0;i<deg;i++) if(tp[i])
for(int j=0;j<deg;j++)
c[i+j]=add(c[i+j],mul(tp[i],tp2[j]));
const int inv=power(A[deg],mod-2);
for(int i=2*deg-2;i>=deg;i--) if(c[i]) {
const int t=mul(c[i],inv);
for(int j=i;i-j<=deg;j--)
c[j]=dec(c[j],mul(t,A[deg-(i-j)]));
}
}
inline int getf(int b,int ans=0) {
memset(C,0,sizeof(C)); memset(B,0,sizeof(B)); C[1]=1; B[0]=1;
if(deg==1) C[1]=0, C[0]=mul(A[0],power(dec(0,A[1]),mod-2));
for(;b;b>>=1,mul(C,C,C)) if(b&1) mul(B,C,B);
for(int i=0;i<deg;i++) ans=add(ans,mul(B[i],f[i]));
return ans;
}
inline int solve(int lim) {
memset(g,0,sizeof(g)); memset(s,0,sizeof(s));
for(int i=lim;i>=1;i--) {
for(int j=1;j*i<=lim;++j) {
for(int k=1;k<=j;k++) {
g[j][i]=add(g[j][i],mul((k==1) ? 1 : s[k-1], (k==j) ? 1 : s[j-k]));
if(k!=lim) g[j][i]=add(g[j][i],mul((k==1) ? 1 : s[k-1], g[j-k][i]));
} g[j][i]=mul(g[j][i],dec(1,q));
}
for(int j=1;j*i<=lim;++j) {
s[j]=add(s[j],g[j][i]);
s[j]=mul(s[j],pw[j]);
}
}
memset(s,0,sizeof(s)); memset(f,0,sizeof(f)); s[0]=1;
for(int j=1;j<=lim;j++)
for(int i=1;i*j<=lim;++i)
s[j]=add(s[j],mul(g[j][i],pw[i*j]));
deg=lim+1;
for(int i=deg;i>=1;i--) s[i]=mul(s[i-1],dec(1,q));
f[0]=1; for(int i=1;i<deg;i++) for(int j=1;j<=i;j++) f[i]=add(f[i],mul(s[j],f[i-j]));
A[deg]=1; for(int i=1;i<=deg;i++) A[deg-i]=dec(0,s[i]);
return mul(getf(n+1),power(dec(1,q),mod-2));
}
int main() {
n=rd(); int k=rd(); q=rd(), q=mul(q,power(rd(),mod-2));
pw[0]=1; for(int i=1;i<K;i++) pw[i]=mul(pw[i-1],q);
cout<<dec(solve(k),solve(k-1));
}