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;
}
posted @ 2017-08-04 16:00  forever97  阅读(307)  评论(0编辑  收藏  举报