HDU 6052 To my boyfriend(悬线法)
【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6052
【题目大意】
给出一个数字矩阵,求子矩阵期望数字种数
【题解】
我们统计[x,y]为其所表示的数字的最左上方的矩形数量,即该格子的贡献值,
我们用悬线法将上边界上移,调整左右边界保证[x,y]为数字左上边界,
那么x及其以下的部分都可以作为下边界,顺序统计即可,
由于障碍点的顺序设置保证了二维的偏序性,不会出现重复统计贡献。
【代码】
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; const int N=110; int n,m,c,l[N],r[N],row[N*N][N]; LL Cal(int x,int y,int c){ LL res=0; for(int i=1;i<=x;i++)l[i]=0,r[i]=m+1; for(int i=1;i<y;i++)l[row[c][i]]=i; for(int i=m;i>y;i--)r[row[c][i]]=i; int h=row[c][y]; for(int i=x-1;i>h;i--)l[i]=max(l[i],l[i+1]),r[i]=min(r[i],r[i+1]); for(int i=x;i>h;i--)res+=(LL)(r[i]-y)*(y-l[i])*(n-x+1); return res; } int T; int main(){ scanf("%d",&T); while(T--){ memset(row,0,sizeof(row)); scanf("%d%d",&n,&m); LL ans=0,tot=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&c); ans+=Cal(i,j,c); row[c][j]=i; tot+=1LL*i*j; } }printf("%.9f\n",1.0*ans/tot); }return 0; }
愿你出走半生,归来仍是少年