题解 CF618G【Combining Slimes】
(这题过程很长,所以我直接把我写的 PPT 截图挂上来了。)
代码:
写代码的时间比较早,变量名与 PPT 中不同,仅供参考。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lf long double
namespace IO{//by cyffff
}
struct Matrix{
lf a[55][55];
Matrix(){ memset(a,0,sizeof(a)); }
inline lf* operator[](const int &x){
return a[x];
}
inline void epi(){
for(int i=0;i<50;i++)
a[i][i]=1;
}
inline friend Matrix operator*(Matrix a,Matrix b){
Matrix c;
for(int i=0;i<50;i++)
for(int j=0;j<50;j++)
for(int k=0;k<50;k++)
c.a[i][j]+=a.a[i][k]*b.a[k][j];
return c;
}
}A,B;
inline Matrix qpow(Matrix A,int b){
Matrix B;
B.epi();
while(b){
if(b&1) B=B*A;
A=A*A;
b>>=1;
}
return B;
}
/*
a(i,j)表示序列长度限制为i,最左侧出现j的概率。
b(i,j)表示序列长度限制为i,第一次出现的是2,最左侧出现j的概率。
*/
int n;
lf p,a[55][55],b[55][55],c[55][55],d[55][55],dp[55][55];
int main(){
scanf("%d %Lf",&n,&p);
p/=1e9;
a[1][1]=p;
a[1][2]=1-p;
b[1][2]=1-p;
for(int i=2;i<=50;i++){
a[i][1]=p;
a[i][2]=1-p+p*p;
b[i][2]=1-p;
for(int j=3;j<=50;j++)
a[i][j]=a[i][j-1]*a[i-1][j-1],
b[i][j]=b[i][j-1]*a[i-1][j-1];
}
for(int i=1;i<=50;i++)
for(int j=1;j<=50;j++)
c[i][j]=a[i][j]*(1-a[i-1][j]),
d[i][j]=b[i][j]*(1-a[i-1][j]);
dp[1][1]=1,dp[1][2]=2;
for(int i=2;i<=50;i++){
lf sum=0;
for(int k=2;k<=50;k++)
dp[i][1]+=dp[i-1][k]*d[i-1][k],sum+=d[i-1][k];
dp[i][1]=1+dp[i][1]/sum;
for(int j=2;j<=50;j++){
sum=0;
for(int k=1;k<j;k++)
dp[i][j]+=dp[i-1][k]*c[i-1][k],sum+=c[i-1][k];
dp[i][j]=j+dp[i][j]/sum;
}
}
if(n<=50){
lf ans=0;
for(int i=1;i<=n+1;i++)
ans+=dp[n][i]*c[n][i];
printf("%.6Lf",ans);
return 0;
}
A[0][0]=B[0][0]=1;
for(int i=1;i<=50;i++)
A[0][i]=dp[50][i];
lf sum=0;
for(int j=2;j<=50;j++)
B[j][1]+=d[50][j],sum+=d[50][j];
for(int j=2;j<=50;j++)
B[j][1]/=sum;
B[0][1]=1;
for(int i=2;i<=50;i++){
sum=0;
for(int j=1;j<i;j++)
B[j][i]+=c[50][j],sum+=c[50][j];
for(int j=1;j<i;j++)
B[j][i]/=sum;
B[0][i]=i;
}
A=A*qpow(B,n-50);
lf ans=0;
for(int i=1;i<=50;i++)
ans+=A[0][i]*c[50][i];
printf("%.6Lf",ans);
}
再见 qwq~