有麻烦请先笑笑

萩 x H

我的时间很少,但我却有很多想法

3月26-27号训练笔记

1:hdu6052 - H - To my boyfriend

题意:给一个nm矩阵,每个方格写一个1~nm范围内的数,任取一个子矩阵,求不同的数的个数的期望值。
题解:遇见这种题型,果断转化成求每个数字所在的矩阵个数的期望值,这是一个很经典的期望问题,对于这个问题可以这样做,求每个数字有几个子矩阵包含,遍历一遍对他分别求包含它的子矩阵个数,但是为了避免重复,计算一个格子的时候,不能包含上面的和同层右边的格子,这样就一定不会重复计算。
定义pre[c][i][j]代表遍历到当前格子,颜色c在第i行第j列的时候,在他上面最近的c颜色的格子的下标值,但是我们是边遍历边求答案,所以i这一维可以省略,再用一套单调栈就可以求。

#include<bits/stdc++.h>
using namespace std;
#define f(i,a,b) for(int i=a;i<=b;++i)
#define ll long long
#define N 105
inline ll read(){ll x;scanf("%lld",&x);return x;}
ll pre[N*N][N],now[N*N][N],st[N],sum[N],tp=0,a[N][N],lt[N*N];
ll color,x,y;
ll counts(ll l,ll r)
{
	tp=0;
	st[0]=l-1;
	sum[l-1]=0;
	ll res=0;
	f(i,l,r)
	{
		while(tp&&pre[color][st[tp]]<pre[color][i]) tp--;
		sum[i]=(x-pre[color][i])*(i-st[tp])+sum[st[tp]];
		res+=sum[i];
		st[++tp]=i;
	}
	return res;
}
int main()
{
	ll T=read();
	while(T--) 
	{
		memset(pre,0,sizeof pre);
		memset(now,0,sizeof now);
		ll n=read(),m=read(),ans=0;
		f(i,1,n)
			f(j,1,m)
				a[i][j]=read();
		f(i,1,n)
		{
			memset(lt,0,sizeof lt);
			f(j,1,m)
			{
				color=a[i][j];
				x=i,y=j;
				ans+=(n-i+1)*(counts(lt[color]+1,m)-counts(lt[color]+1,j-1)-counts(j+1,m));
				//cout<<"grid : "<<ans<<endl;
				lt[a[i][j]]=j;
			}
			f(j,1,m) pre[a[i][j]][j]=i;
		}
		//cout<<"ans="<<ans<<endl;
		ll s=n*m*(n+1)*(m+1)/4;
		printf("%.9lf\n",(double)ans/s);
	}
	return 0;
}
posted @ 2021-03-29 21:07  萩xh  阅读(37)  评论(0编辑  收藏  举报