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]);
	
}
posted @ 2021-11-01 17:15  After_rain  阅读(48)  评论(0)    收藏  举报