• 2019牛客暑期多校训练营(第二场)


    A.Eddy Walker

    题意 给你长度为n的圈(共有n个点(0~n-1),按顺序形成一个环), 每次随机的向左走一步或者向右走一步, 问你最后将所有点走过至少一遍,最后一步停留在m点的概率是多少。

    思路:这题主要是很少有人能把题目读懂,像篇阅读理解一样的,看懂后就会发现你会发现落在0到n-1上的概率是相同的,T组样例,每次的概率都要乘以之前的概率,最后记得加上特判

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
     
    const int mod=1e9+7;
    ll n, m, ans;
    
    ll mod_pow(ll x, ll n)
    {
        ll res = 1;
        while (n>0) {
            if (n&1) res = res*x%mod;
            x = x*x%mod;
            n >>= 1;
        }
        return res;
    }
     
    int main()
    {
        int t;
        scanf("%d",&t);
         
        ans = 1;
        while(t--){
            scanf("%d%d",&n,&m);
            if(n==1 && m==0) ans *= 1;   
            else if(m==0) ans *= 0;
            else ans = (ans*mod_pow(n-1,mod-2))%mod;   
            printf("%lld
    ",ans); 
        }
        return 0;
    }
    View Code

    H.Second Large Rectangle

    题意:给出由01组成的矩阵,求求全是1的次大子矩阵。

    思路:

    单调栈

    全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如:

    1 0 0
    1 1 1
    1 1 1

    有篇博主的代码细节处理的很好,由于矩阵每行的长度一致,则不必重复在数组末尾标记0;然后由于j是从1,最开始如果push进0的话,有两个好处:

      1.可以不受栈之前“残留”的元素m+1的影响

      2.不用再判断栈是某为空来确定wid的值

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e3 + 7;
    
    int n, m, ans;
    string str[N];
    int h[N], mx1, mx2;
    stack <int> s;
    
    void solve(int x)
    {
        if(x > mx1)
            mx2 = mx1, mx1 = x;
        else if(x > mx2) mx2 = x;
    }
    int main()
    {
        scanf("%d%d",&n, &m);
        for(int i = 1; i <= n; i++) {
            cin >> str[i];
            for(int j = 1; j <= m; j++) {
                if(str[i][j-1] == '1') h[j] += 1;
                else h[j] = 0;
            }
            s.push(0);
            for(int j = 1; j <= m + 1; j++) {
                while(h[j] < h[s.top()]) {
                    int index = s.top(); s.pop();
                    int x = j - 1 - s.top(), y = h[index];
                    solve(x * y);
                    solve((x - 1)* y);
                    solve(x * (y - 1));
                }
                s.push(j);
            }
        }
        cout << mx2 << endl;
    }
    View Code

     悬线法

    通过悬线法,可以找到以点(i,j)为底的极大矩形。

    u[i][j]、l[i][j]、r[i][j]分别表示以为底的极大矩形的上边界,左边界,右边界;

    首先预处理:找到点(i,j)可以沿伸的的上端点、左端点,右端点 (dp)

    For i = 1 to n
        For j = 1 to m
            u[i][j] = (i-1,j)==1 ? u[i-1][j] : i;
            l[i][j] = (i,j-1)==1 ? l[i][j-1] : j;
        For j = m to 1
            r[i][j] = (i,j+1)==1 ? r[i][j+1] : j;

    如图找到了(4,3)  的   上端点、左端点,右端点,但是这些边界并没有组成一个矩形,可以(4,3)的上端点为上边界,找到左右边界,这样就可以找到一个以点(4,3)为底、以点(4,3)上界为高的极大矩形。

    For i = 1 to n
        For j = 1 to m
            if (i-1,j)==1
                l[i][j] = max(l[i][j], l[i-1][j]
                r[i][j] = min(r[i][j], r[i-1][j]
    矩形面积就是 (r[i][j] − l[i][j] + 1) ∗ (i − u[i][j] + 1)
    Code
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1e3+100;
    
    int n, m;
    int g[N][N];
    int u[N][N], l[N][N], r[N][N];
    int hh, ll, rr, bb;
    char str[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++){
            scanf("%s",str+1);
            for(int j = 1; j <= m; j++ ){
                if(str[j] == '1') g[i][j] = 1;
                else g[i][j] = 0;
            }
        }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                u[i][j] = l[i][j] = r[i][j] = 0;
        
        
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(g[i][j] == 0) continue;
                    u[i][j] = g[i-1][j] == 1 ? u[i-1][j] : i;
                    l[i][j] = g[i][j-1] == 1 ? l[i][j-1] : j;
            }
            for(int j = m; j >= 1; j--){
                if(g[i][j] == 0) continue;
                r[i][j] = g[i][j+1] == 1 ? r[i][j+1] : j;
            }
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(g[i][j] == 0) continue;
                if(g[i-1][j] == 1) {
                    l[i][j] = max(l[i][j], l[i-1][j]);
                    r[i][j] = min(r[i][j], r[i-1][j]);
                }
                if(ans<(r[i][j]-l[i][j]+1)*(i-u[i][j]+1)){
                    hh = u[i][j] , bb =i;
                    rr = r[i][j],ll=l[i][j];
                    ans = (r[i][j]-l[i][j]+1)*(i-u[i][j]+1);
                }
            }
        }
        int ans2 = max((rr-ll)*(bb-hh+1), (rr-ll +1)*(bb-hh));
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(g[i][j] == 0) continue;
                if(hh==u[i][j]&&bb==i&&ll==l[i][j]&&rr==r[i][j])
                    continue;
                if(ans2<(r[i][j]-l[i][j]+1)*(i-u[i][j]+1)){
                    ans2=(r[i][j]-l[i][j]+1)*(i-u[i][j]+1);
                }
            }
        }
        cout << ans2 << endl;
        return 0;
    }
    View Code

     悬线法的学习可以参考这篇博客(小声bb:虽然感觉现在没什么用,还不如单调栈)

    https://blog.csdn.net/dbc_121/article/details/77503611

  • 相关阅读:
    决战72hours
    学习中的十七条建议
    数学建模终结篇
    数学建模(7)建模开始
    ASP升级程序
    为blog挑选logo
    Mysql源代码分析系列(4): 主要调用流程(续)转载
    AS学习步骤
    什么是敏捷软件测试[转]
    Mysql源代码分析(6): Plugin架构介绍(续)转载
  • 原文地址:https://www.cnblogs.com/wizarderror/p/11226316.html
Copyright © 2020-2023  润新知