2021提高组十连测day8
T1
发现,第一枪可以将原来的矩阵划分成四块,总的期望可以由每一个第一枪位置所划分的每一个快内,继续开枪,沿着你划分的位置走的长度的累加和
考虑如何做这个问题
相当于是 对于一个子矩阵,统计一下有多少种方式可以到他的上下左右边界
不妨记
\(g[x_1][x_2][y_1][y_2][0-3]\)表示兔子在子矩阵 $ (x1,y1) -> (x_2,y_2)$里面,跑到上下左右边界上的期望次数
考虑如何转移
不妨 枚举一下 在这个子矩阵里面第一枪 开在哪里,那你这个子矩阵不就是被分为四个子矩阵了嘛
直接就暴力转移就好了
记\(f[x_1][y_1][x_2][y_2]表示兔子在子矩阵(x_1,y_1)->(x_2,y_2)里面,跑动的期望距离\)
类似上面的转移,任然是枚举一下第一枪开的位置, 由四个块之和 + 各个位置跑到边界的期望次数 * 到边界的长度
#include<bits/stdc++.h>
#define MAXN 35
using namespace std;
int n,m,K,a[MAXN][MAXN];
int vis[MAXN][MAXN][MAXN][MAXN];
double f[MAXN][MAXN][MAXN][MAXN][5];
/*
左 1
下 2
右 3
上 4
*/
double* dfs(int l1 , int r1 , int l2 , int r2){
double *res = f[l1][r1][l2][r2];
if(vis[l1][r1][l2][r2])return res;
vis[l1][r1][l2][r2] = 1;
double *p1,*p2,*p3,*p4;
double num = 0;
for(int i = l1 + 1 ; i <= r1 - 1 ; i++){
for(int j = l2 + 1 ; j <= r2 - 1 ; j++){
if(!a[i][j])continue;
++num;
p1=dfs(l1,i,l2,j);
p2=dfs(l1,i,j,r2);
p3=dfs(i,r1,l2,j);
p4=dfs(i,r1,j,r2);
res[0]+=p1[0]+p2[0]+p3[0]+p4[0]+
(i-l1)*(p1[3]+p2[3]+p3[1]+p4[1])+
(j-l2)*(p1[4]+p2[3]+p3[4]+p4[3])+
(r1-i)*(p1[4]+p2[4]+p3[2]+p4[2])+
(r2-j)*(p1[2]+p2[1]+p3[2]+p4[1]);
res[1]+=p1[1]+p1[3]+p2[3]+p3[1];
res[2]+=p2[2]+p1[2]+p2[1]+p4[1];
res[3]+=p3[3]+p1[4]+p3[4]+p4[3];
res[4]+=p4[4]+p2[4]+p3[2]+p4[2];
}
}
if(!num)return res;
res[0]=res[0]/num+2*(r1-l1+r2-l2);
for(int i=1;i<=4;++i)
res[i]=res[i]/num+1;
return res;
}
int main(){
cin>>n>>m;int x,y;
cin>>K;
for(int i = 1 ; i <= K ; i++){
cin>>x>>y;
a[x][y] = 1;
}
double *ans;
ans = dfs(0 , n , 0 , m);
printf("%.10f\n" , ans[0]);
}

浙公网安备 33010602011771号