Hdu-6052 To my boyfriend(單調棧)

Dear Liao 

I never forget the moment I met with you. You carefully asked me: "I have a very difficult problem. Can you teach me?". I replied with a smile, "of course". You replied:"Given a matrix, I randomly choose a sub-matrix, what is the expectation of the number of **different numbers** it contains?" 

Sincerely yours, 
Guo
InputThe first line of input contains an integer T(T≤8) indicating the number of test cases. 
Each case contains two integers, n and m (1≤n, m≤100), the number of rows and the number of columns in the grid, respectively. 
The next n lines each contain m integers. In particular, the j-th integer in the i-th of these rows contains g_i,j (0≤ g_i,j < n*m). OutputEach case outputs a number that holds 9 decimal places. Sample Input
1
2 3
1 2 1
2 1 2
Sample Output
1.666666667

        
  
Hint
6(size = 1) + 14(size = 2) + 4(size = 3) + 4(size = 4) + 2(size = 6) = 30  / 18 = 6(size = 1) + 7(size = 2) + 2(size = 3) + 2(size = 4) + 1(size = 6)

        
 分析:我們考慮計算每種顏色的貢獻和,我們將某個子矩陣中對答案有貢獻的方格定義爲這個子矩陣的所有同色方格中最高上左的那個(先上後左),然後我們再轉來計算每個方格貢獻的子矩陣個數,這個用單調棧可以O(n)計算,總複雜度O(n^3).
#include <bits/stdc++.h>
#define N 105
using namespace std;
typedef long long ll;
struct thing
{
    int x,n;
    thing(){};
    thing(int a,int b){x = a,n = b;}
}Stack[N];
int T,n,m,tot,c[N][N],pre[N*N][N],Pre[N*N][N],vis[N*N];
ll ans;
int Count(int l,int r,int i,int j,int col)
{
    int sum = 0,t = 0,ans = 0;
    for(int k = l;k <= r;k++)
    {
        int d = (i == pre[col][k] && k >= j) ?  i - Pre[col][k] : i - pre[col][k];
        if(!d) t = sum = 0;
        else
        {
            thing u = thing(d,1);
            while(t && Stack[t].x >= u.x)
            {
                sum -= Stack[t].x*Stack[t].n;
                u.n += Stack[t].n;
                t--;
            }
            sum += u.x*u.n*1ll;
            Stack[++t] = u;
            ans += sum;
        }
     }
    return ans;
}
int main()
{
   scanf("%d",&T);
   while(T--)
   {
       memset(pre,0,sizeof(pre));
       memset(vis,0,sizeof(vis));
       tot = 0,ans = 0;
       scanf("%d%d",&n,&m);
       for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
        {
            scanf("%d",&c[i][j]);
            if(!vis[c[i][j]]) tot++,vis[c[i][j]] = 1;
        }
       for(int i = 1;i <= n;i++)
       {
          for(int j = 1;j <= m;j++)
          {
              Pre[c[i][j]][j] = pre[c[i][j]][j];
              pre[c[i][j]][j] = i;
          }
          for(int j = 1;j <= m;j++)
          {
             int col = c[i][j];
             ans += (n-i+1ll)*(Count(1,m,i,j,col) - Count(1,j-1,i,j,col) - Count(j+1,m,i,j,col));
          }
       }
       printf("%.9f\n",ans*4.0/(n*(n+1)*m*(m+1)));
   }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章