题解:P5750 [NOI1999] 钉子和小球
思路
明显的概率DP,设 \(f_{i,j}\) 为小球落到位置 \((i,j)\) 的概率,容易得到状态转移的方法。
当 \(a_{i-1,j-1}\) 有钉子时,\(f_{i,j}=f_{i,j}+\frac{f_{i-1,j-1}}{2} \times 50\%\)。
当 \(a_{i-1,j}\) 有钉子时,\(f_{i,j}=f_{i,j}+f_{i-1,j} \times 50 \%\)。
当 \(a_{i-2,j-1}\) 没有钉子时,\(f_{i,j}=f_{i,j}+f_{i-2,j-1}\)。
由于本题需要输出分数,所以我们可以用一个结构体储存答案。
于是这题就做完了。
代码
#include<bits/stdc++.h>
using namespace std;
#define int __int128
const int N=60,mod=1e9+7;
int n,m;
char a[N][N];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
void write(int x){
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
return;
}
int gcd(int a,int b){ return b?gcd(b,a%b):a; }
int lcm(int a,int b){ return a*b/gcd(a,b); }
struct node{
int fz,fm;
node operator +(const node x) const{
if(fm==0) return x;
if(x.fm==0) return *this;
node res=(node){fz,fm};
int u=lcm(res.fm,x.fm);
res.fz=(u/fm)*fz+(u/x.fm)*x.fz;
res.fm=u;
int g=gcd(res.fz,res.fm);
if(!g) return res;
res.fz/=g;
res.fm/=g;
return res;
}
node operator *(const node x) const{
node res=(node){fz,fm},resx=(node){x.fz,x.fm};
int g1=gcd(res.fz,resx.fm),g2=gcd(res.fm,resx.fz);
res.fz/=g1;resx.fm/=g1;
res.fm/=g2;resx.fz/=g2;
res.fz*=x.fz;
res.fm*=x.fm;
if(!res.fz || !res.fm) return (node){0,1};
int g=gcd(res.fz,res.fm);
if(!g) return res;
res.fz/=g;
res.fm/=g;
return res;
}
void output(){
if(fz==0){
cout<<"0/1";
return;
}
int g=gcd(fz,fm);
fz/=g;
fm/=g;
write(fz);
cout<<'/';
write(fm);
}
}f[N][N];
signed main(){
n=read();m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
}
a[i][0]='.';
}
f[1][1].fz=f[1][1].fm=1;
for(int i=2;i<=n+1;i++){
for(int j=1;j<=i;j++){
f[i][j]=(node){0,1};
if(i>2 && j>1 && a[i-2][j-1]=='.'){
f[i][j]=f[i][j]+f[i-2][j-1];
}
if(a[i-1][j-1]=='*') f[i][j]=f[i][j]+f[i-1][j-1]*(node){1,2};
if(a[i-1][j]=='*') f[i][j]=f[i][j]+f[i-1][j]*(node){1,2};
}
}
f[n+1][m+1].output();
return 0;
}

浙公网安备 33010602011771号