zoukankan      html  css  js  c++  java
  • 01矩阵系列(计数/最大查询)

    51Nod 1291

    题意:600*600的01矩阵,统计宽i高j的全1矩阵的个数。

    题解:枚举矩阵的下边界,对于每个下边界,统计所有宽极大的矩形的答案(高度可以用差分)。O(nm)的复杂度统计完之后,我们已知所有高度的宽极大的答案,列一下式子发现两次前缀和就是最后答案。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define st first
     4 #define nd second
     5 #define rep(i, a, b) for(int i=(a); i<(b); i++)
     6 #define sz(x) (int)x.size()
     7 #define de(x) cout<< #x<<" = "<<x<<endl
     8 #define dd(x) cout<< #x<<" = "<<x<<" "
     9 typedef long long ll;
    10 typedef pair<int, int> pii;
    11 typedef vector<int> vi;
    12 
    13 const int N = 666;
    14 int n, m, top;
    15 int u[N], sta[N];
    16 ll c[N][N];
    17 char s[N];
    18 
    19 int main() {
    20     scanf("%d%d", &n, &m);
    21     for(int i = 1; i <= n; i++) {
    22         scanf("%s", s+1);
    23         for(int j = 1; j <= m; j++)
    24             u[j] = (s[j] == '1')? u[j]+1: 0;
    25         top = 0;
    26         sta[top++]=0;
    27         for(int j = 1; j <= m+1; j++) {
    28             while(u[sta[top-1]] > u[j]) {
    29                 ++c[max(u[sta[top-2]], u[j])+1][j-sta[top-2]-1];//维护单调上升的栈, 看每个柱块向左和向右的最大延伸距离, 即为宽度
    30                 --c[u[sta[top-1]]+1][j-sta[top-2]-1];            //枚举i为底边, 对高度范围为[max(u[sta[top-2]],u[j])+1, u[sta[top-1]]], 宽度为j-sta[top-2]-1的矩形加1
    31                 --top;
    32             }
    33             while(top && u[sta[top-1]] == u[j]) --top;
    34             sta[top++] = j;
    35         }
    36     }
    37     for(int i = 2; i <= n; i++) for(int j = 1; j <= m; j++) c[i][j] += c[i-1][j]; //c1[i, j]: 高为i (n^2) 的连通块, 只统计最长宽度的。
    38     for(int i = 1; i <= n; i++) {
    39         for(int j = m-1; j; j--) c[i][j] += c[i][j+1];    //c2[i, j]: 高i宽 >= j的连通块的个数
    40         for(int j = m-1; j; j--) c[i][j] += c[i][j+1];  //c3[i, j]: 高i宽j的全1矩阵的个数
    41     }
    42     for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) printf("%lld%c", c[i][j], " 
    "[j == m]);
    43     return 0;
    44 }
    45 /*
    46 3 3
    47 011
    48 110
    49 110
    50 如何得到c1? 暴力的话, c1是枚举n^2的上下边界, 优化后, 变成枚举直方图的最底边,快速统计各个不同的上顶边。这个可以通过单调栈+差分解决。求前缀和后就得到c1。
    51 总的时间复杂度为O(nm).
    52 c1
    53 0 3 0
    54 1 1 0
    55 1 0 0
    56 c2
    57 3 3 0
    58 2 1 0
    59 1 0 0
    60 c3
    61 6 3 0
    62 3 1 0
    63 1 0 0
    64 
    65 */

    Wannafly挑战赛12 D

    题意:1e9*1e9的01矩阵,1的个数c个(c <= 5000),统计全0矩阵的个数。

    题解:所有情况 减去 包含1的。包含1的矩阵这么算:对于每个1,统计包含这个1而不包含之前的1的矩阵个数。思想类似于带禁手的马跳棋盘方案数计数。时间复杂度 O(c^2)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define st first
     4 #define nd second
     5 typedef long long ll;
     6 const int mod = 1e9+7;
     7 pair<int, int> s[5111];
     8 int main() {
     9     int n, m, c;
    10     scanf("%d%d%d", &n, &m, &c);
    11     for(int i = 1, x, y; i <= c; i++) scanf("%d%d", &x, &y), s[i] = {x, y};
    12     sort(s+1, s+c+1);
    13     long long ans = 0;
    14     for(int i = 1; i <= c; i++){
    15         int l = 0, r = m+1;
    16         for(int j = i-1; ~j; j--){                                                            //从下往上从左往右枚举之前的点
    17             ans += (r-s[i].nd)*(n-s[i].st+1LL)%mod*(s[j+1].st-s[j].st)%mod*(s[i].nd-l)%mod;    //上边界为s[j].st ~ s[j+1].st
    18             ans %= mod;
    19             if(s[j].nd > s[i].nd) r = min(r, s[j].nd);
    20             if(s[j].nd < s[i].nd) l = max(l, s[j].nd);
    21         }
    22     } 
    23     //n*m矩阵的子矩阵个数 = 左右两边界 * 上下两边界 
    24     long long cnt = (n*(n+1LL)/2%mod)*(m*(m+1LL)/2%mod)%mod;
    25     ans = (cnt-ans)%mod;
    26     if(ans < 0) ans += mod;
    27     printf("%lld
    ", ans);
    28     return 0;
    29 }

    Codeforces 713D Animals and Puzzle

    题意:一个n*m的01矩阵,Q个询问,每次询问一个矩形区域内,最大的全1正方形的边长是多少?

    题解:dp[0][0][i][j]表示以(i, j)为右下角的正方形的最长边长。RMQ后,二分答案即可。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const int N = 1e3+10;
     7 int x1, y1, x2, y2, n, m;
     8 int a[N][N];
     9 int dp[10][10][N][N];
    10 int Log[N];
    11 int ask(int x1, int y1, int x2, int y2){
    12     int k1 = Log[x2-x1+1], k2 = Log[y2-y1+1];
    13     int ans = max(dp[k1][k2][x1][y1], dp[k1][k2][x1][y2-(1<<k2)+1]);
    14     ans = max(ans, dp[k1][k2][x2-(1<<k1)+1][y1]);
    15     ans = max(ans, dp[k1][k2][x2-(1<<k1)+1][y2-(1<<k2)+1]);
    16     return ans;
    17 }
    18 bool test(int l){
    19     //dp[0][x1][y1] dp[0][x2-x+1][y2-x+1]
    20     int ret = ask(x1+l-1, y1+l-1, x2, y2);
    21     return ret >= l;
    22 }
    23 void init(){
    24     for(int i = 1; i <= Log[n]; i++)
    25         for(int x = 1; x+(1<<i)-1 <= n; x++)
    26             for(int y = 1; y <= m; y++)
    27                 dp[i][0][x][y] = max(dp[i-1][0][x][y], dp[i-1][0][x+(1<<i-1)][y]);
    28     for(int i = 0; i <= Log[n]; i++)
    29         for(int j = 1; j <= Log[m]; j++)
    30             for(int x = 1; x+(1<<i)-1 <= n; x++)
    31                 for(int y = 1; y+(1<<j)-1 <= m; y++)
    32                     dp[i][j][x][y] = max(dp[i][j-1][x][y], dp[i][j-1][x][y+(1<<j-1)]);
    33 }
    34 int main(){
    35     for(int i = 2; i < N; i++) Log[i] = Log[i>>1]+1;
    36     scanf("%d%d", &n, &m);
    37     for(int i = 1; i <= n; i++)
    38         for(int j = 1; j <= m; j++){
    39             scanf("%d", &a[i][j]);
    40             if(a[i][j] == 0) dp[0][0][i][j] = 0;
    41             else{
    42                 int len = min(dp[0][0][i-1][j], dp[0][0][i][j-1]);
    43                 dp[0][0][i][j] = len+a[i-len][j-len];
    44             }
    45         }
    46     init();
    47 
    48     int t; scanf("%d", &t);
    49     while(t--){
    50         scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    51         int L = 0, R = min(x2-x1+1, y2-y1+1);
    52         while(L < R){
    53             int M = L+R+1 >> 1;
    54             if( test(M) )
    55                 L = M;
    56             else
    57                 R = M-1;
    58         }
    59         printf("%d
    ", L);
    60     }
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    bzoj 1030 [JSOI2007]文本生成器
    Swift 学习笔记 (闭包)
    Swift 学习笔记 (函数)
    HTML 学习笔记 JQueryUI(Interactions,Widgets)
    HTML 学习笔记 JQuery(表单,表格 操作)
    HTML 学习笔记 JQuery(animation)
    HTML 学习笔记 JQuery(盒子操作)
    HTML 学习笔记 JQuery(事件)
    HTML 学习笔记 JQuery(DOM 操作3)
    HTML 学习笔记 JQuery(DOM 操作2)
  • 原文地址:https://www.cnblogs.com/dirge/p/10034268.html
Copyright © 2011-2022 走看看