悬线法学习笔记

悬线法学习笔记

单调栈可以解决的问题,一部分可以用悬线法解决,悬线法更容易理解,代码量差不多。

SPOJ.com - Problem HISTOGRA

找元素的左右扩展区间。如果用选线法处理的话,定义 Li 是可扩展做区间,如果 aiaLi1,的话可以继续继承 LLi1 这可以看成一个递归的过程,均摊复杂度线性。

int n;
void solve2() {
    vector<int> h(n + 1);
    rep(i,1,n) cin >> h[i];
    vector<int> L(n + 1), R(n + 1);
    iota(L.begin(),L.end(),0);
    iota(R.begin(),R.end(),0);
    rep(i,1,n) while(L[i] > 1 and h[i] <= h[L[i] - 1]) L[i] = L[L[i] - 1];
    dec(i,n,1) while(R[i] < n and h[i] <= h[R[i] + 1]) R[i] = R[R[i] + 1];
    ll ans = 0;
    rep(i,1,n) ans = max(ans, 1ll * h[i] * (R[i] - L[i] + 1));
    cout << ans << "\n";
}

P4147 玉蟾宫 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

最大子矩形板子题,可以发现,就是二维的悬线,需要处理出一个 a 表示一个“纵向的前缀和”表示 hight。之后跑板子就行了。

void solve()
{    
    int n,m; cin >> n >> m;
    vector<vector<int>> a(n + 1,vector<int>(m + 1));
    rep(i,1,n) rep(j,1,m) {
        char t; cin >> t;
        if(t == 'R') continue;
        a[i][j] = a[i - 1][j] + 1;
    }
    int ans = 0;
    rep(i,1,n) {
        vector<int> L(m + 1), R(m + 1);
        rep(j,1,m) L[j] = R[j] = j;
        auto &b = a[i];
        rep(j,1,m) while(L[j] > 1 and b[j] <= b[L[j] - 1]) L[j] = L[L[j] - 1];
        dec(j,m,1) while(R[j] < m and b[j] <= b[R[j] + 1]) R[j] = R[R[j] + 1];
        rep(j,1,m) ans = max(ans, (R[j] - L[j] + 1) * b[j] * 3);  
    }
    cout << ans;
}

[P1169 ZJOI2007]棋盘制作 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

求01交替的最大子矩阵,需要处理的就是悬线左右移动时的要保证01交替。

做递推时,应该判断 a[i][Rj]a[i][Rj+1] 表示相邻的不同数。

while(L[j] > 1 and h[j] <= h[L[j] - 1] and a[i][R[j]] ^ a[i][R[j] + 1])
                L[j] = L[L[j] - 1];
void solve()
{    
    int n,m; cin >> n >> m;
    vector<vector<int>> a(n + 1,vector<int>(m + 1));
    rep(i,1,n) rep(j,1,m) cin >> a[i][j];
    vector<vector<int>> s(n + 1,vector<int>(m + 1));
    rep(j,1,m) s[1][j] = 1;
    rep(i,2,n) rep(j,1,m) {
        if(a[i][j] ^ a[i - 1][j]) 
            s[i][j] = s[i - 1][j] + 1;
        else s[i][j] = 1;
    }
    int ans1 = 0, ans2 = 0;
    rep(i,1,n) {
        auto &h = s[i];
        vector<int> L(m + 1),R(m + 1);
        rep(j,1,m) L[j] = R[j] = j;
        rep(j,1,m) 
            while(L[j] > 1 and h[j] <= h[L[j] - 1] and a[i][R[j]] ^ a[i][R[j] + 1])
                L[j] = L[L[j] - 1];
        dec(j,m,1) 
            while(R[j] < m and h[j] <= h[R[j] + 1] and a[i][R[j]] ^ a[i][R[j] + 1])
                R[j] = R[R[j] + 1];
        rep(j,1,m) {
            ans1 = max(ans1, min(h[j], R[j] - L[j] + 1) * min(h[j], R[j] - L[j] + 1));
            ans2 = max(ans2, h[j] * (R[j] - L[j] + 1));
        }
    }
    cout << ans1 << "\n" << ans2;
}

极大矩阵计数,看下面例题。

2022牛客国庆集训派对day6 A(极大矩阵计数) - Mxrurush - 博客园 (cnblogs.com)

posted @   Mxrurush  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示