• 单调队列 + 组合数统计 Gym 101102D


    题目链接:http://codeforces.com/gym/101102/problem/D

    题目大意:给你一个n*m的矩阵,矩阵里面的数值范围为[1,1e9]。这个矩阵有一个值,如果相邻的多个数字是一样的,那么val += 他们的组合数,例如 1 1 1,那么就是val就是6.

    问最后这个矩阵是val是多少?

    思路:

    我们固定右端点,先统计出上方有几个和他数值相同的数字,并把这个定义成这个位置的高,然后每次往统计以这个点为右下角的端点数即可。然后暴力右下角就是O(n*n)

    我们发现,如果要每次暴力相同的数字,那么要知道前面有几个数字的高度,然后O(n)的暴力一遍是可以的,但是这样会TLE

    所以我们知道,如果高度是>=目前的h[i][j]的高度的,那么我们就ans[i][j] += h[i][j] * (j - k +1),其中k为高度<h[i][j]出现的位置。(这个东西用单调队列或者单调栈维护一下就好了)

    若是出现a[i][j] == a[i][k - 1],那么我们就只需要ans[i][j] += ans[i][k - 1]即可

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 1000 + 5;
    int n, m;
    int h[maxn][maxn], a[maxn][maxn], cnt[maxn][maxn];
    
    int main(){
        int t; cin >> t;
        while (t--){
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= n; i++){
                for (int j = 1; j <= m; j++){
                    scanf("%d", &a[i][j]);
                    h[i][j] = 1;
                    if (a[i - 1][j] == a[i][j]) h[i][j] += h[i-1][j];
                    cnt[i][j] = 0;
                }
            }
            LL res = 0;
            for (int i = 1; i <= n; i++){
                deque<pair<int, int> > que;
                for (int j = 1; j <= m; j++){
                    if (a[i][j] != a[i][j - 1]){
                        while (!que.empty()) que.pop_back();
                        res += h[i][j]; cnt[i][j] = h[i][j];
                        que.push_back(mk(h[i][j], j));
                    }
                    else {
                        pair<int, int> p = mk(h[i][j], j);
                        while (!que.empty()){
                            if (que.back().fi >= p.fi){
                                p.se = que.back().se;
                                que.pop_back();
                            }
                            else break;
                        }
                        cnt[i][j] = h[i][j] * (j - p.se + 1);
                        if (a[i][j] == a[i][p.se - 1]) cnt[i][j] += cnt[i][p.se - 1];
                        res += cnt[i][j];
                        que.push_back(p);
                    }
                }
            }
            printf("%lld
    ", res);
        }
        return 0;
    }
    /*
    549
    3 3
    1 2 1
    1 1 1
    1 1 1
    ans = 25
    
    4564
    3 2
    1 2
    1 1
    1 1
    ans = 13
    
    45609
    3 2
    2 1
    1 1
    1 1
    ans = 13
    */
    View Code
  • 相关阅读:
    数据结构与算法总结
    Java基础总结
    Android基础之View的绘制原理
    安卓面经汇总
    Elasticsearch7.7.0搭建并集成IK分词器
    Linux&Nginx16_Linux安装软件2
    Linux15_Linux命令2
    Linux&Nginx16_Nginx安装3
    Linux&Nginx16_软件安装方式&上传下载1
    Linux15_Linux修改3
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6738715.html
Copyright © 2020-2023  润新知