1. 程式人生 > >LOJ#2304. 「NOI2017」泳池

LOJ#2304. 「NOI2017」泳池

alc 多項式 pac queue IV cst opened amp IT

$n \leq 1e9$底邊長的泳池,好懶啊泥萌自己看題吧,$k \leq 1000$。答案對998244353取膜。

技術分享圖片

技術分享圖片

現在令$P$為安全,$Q$為危險的概率。剛好$K$是極其不好算的,於是來算$\leq K$,然後用$calc(K)-calc(K-1)$解決。$f(i,j)$--$i$行$j$列的矩形中,第$i$行有危險,前$i-1$行都沒有危險,而最大矩形$\leq K$的概率,枚舉最後一個危險格遞推,$f(i,j)=\sum_{k=0}^{j-1}f(i,k)P^{i-1}Qg(i,j-k-1)$,其中$g(i,j)$表示$i$行$j$列矩形的前$i$行都沒危險,而最大矩形$\leq K$的概率,就是$f$的一個前綴和。最後$h(i)$表示$i$列的答案,$h(i)=\sum_{j=i-K}^{i}h(j-1)*Q*g(1,i-j)$,註意一開始的$h(i)+=g(1,i)$。

然後就可以拿到70分。90分的話加個矩陣快速冪,100分加個多項式取膜。只寫70.

技術分享圖片
 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<math.h>
 5 //#include<set>
 6 //#include<queue>
 7 //#include<bitset>
 8 //#include<vector>
 9 #include<algorithm>
10 #include<stdlib.h>
11
using namespace std; 12 13 #define LL long long 14 int qread() 15 { 16 char c; int s=0,f=1; while ((c=getchar())<0 || c>9) (c==-) && (f=-1); 17 do s=s*10+c-0; while ((c=getchar())>=0 && c<=9); return s*f; 18 } 19 20 //Pay attention to ‘-‘ , LL and double of qread!!!!
21 22 int n,K,X,Y,P,Q; 23 const int mod=998244353; 24 int powmod(int a,int b) 25 { 26 int ans=1; 27 while (b) {if (b&1) ans=1ll*ans*a%mod; a=1ll*a*a%mod; b>>=1;} 28 return ans; 29 } 30 31 #define maxn 1011 32 int f[maxn][maxn],g[maxn][maxn],h[maxn],pp[maxn],qq[maxn]; 33 34 int calc(int K) 35 { 36 memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); 37 for (int i=1;i<=K+1;i++) g[i][0]=1; 38 for (int i=K+1;i>1;i--) 39 for (int j=1,to=K/(i-1);j<=to;j++) 40 { 41 for (int k=0;k<j;k++) 42 { 43 f[i][j]=(f[i][j]+1ll*f[i][k]*pp[i-1]%mod*Q%mod*g[i][j-k-1])%mod; 44 f[i][j]=(f[i][j]+1ll*g[i][k]*pp[i-1]%mod*Q%mod*g[i][j-k-1])%mod; 45 } 46 g[i-1][j]=(g[i][j]+f[i][j])%mod; 47 } 48 memset(h,0,sizeof(h)); h[0]=1; 49 for (int i=1;i<=n;i++) 50 { 51 if (i<=K) h[i]=g[1][i]; 52 for (int j=max(1,i-K);j<=i;j++) 53 h[i]=(h[i]+1ll*h[j-1]*Q%mod*g[1][i-j])%mod; 54 } 55 return h[n]; 56 } 57 58 int main() 59 { 60 n=qread(); K=qread(); X=qread(); Y=qread(); P=1ll*X*powmod(Y,mod-2)%mod; Q=(mod+1-P)%mod; 61 pp[0]=qq[0]=1; for (int i=1;i<=K;i++) pp[i]=pp[i-1]*1ll*P%mod,qq[i]=qq[i-1]*1ll*Q%mod; 62 printf("%d\n",(calc(K)-calc(K-1)+mod)%mod); 63 return 0; 64 }
View Code

LOJ#2304. 「NOI2017」泳池