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;
}