2019牛客多校第8场

A题

单调栈的应用

链接:https://ac.nowcoder.com/acm/contest/888/A
来源:牛客网
 

题目描述

Gromah and LZR entered the great tomb, the first thing they see is a matrix of size n×mn\times mn×m, and the elements in the matrix are all 0​ or 1​

LZR finds a note board saying "An all-one matrix is defined as the matrix whose elements are all 1​, you should determine the number of all-one submatrices of the given matrix that are not completely included by any other all-one submatrices".

Meanwhile, Gromah also finds a password lock, obviously the password should be the number mentioned in the note board!

Please help them determine the password and enter the next level.

输入描述:

The first line contains two positive integers n,mn,m_{}n,m​, denoting the size of given matrix.

Following nn_{}n​ lines each contains a string with length mm_{}m​, whose elements are all 00_{}0​ or 11_{}1​, denoting the given matrix.

1≤n,m≤3000

输出描述:

Print a non-negative integer, denoting the answer.

示例1

输入

复制

3 4
0111
1110
0101

输出

复制

5

说明

The 5 matrices are (1,2)−(1,4),  (1,2)−(2,3),  (1,2)−(3,2),  (2,1)−(2,3),  (3,4)−(3,4)

首先预处理一下每一列连续的1的个数h[i][j]和每一行的前缀和sum[i][j],然后枚举行,对于这一列来说如果前面的高于当前,那么就应该把当前这一列向左扩展,然后把前面高于这一列的答案加1后弹出,然后把这一列向左能延伸到的长度和它的高度入栈。

#include<cstdio>
#include<stack>
using namespace std;

const int maxn = 1e4 + 10;
struct node
{
    int h,w;  ///w表示向左能延伸的长度
};
int sum[maxn][maxn],h[maxn][maxn];
int ans,x,n,m,l,r;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n; ++i)
        for(int j = 1;j <= m; ++j)
        {
            scanf("%1d",&x);
            if(x) h[i][j] = h[i - 1][j] + x;   ///这一列的连续的1的数目
            sum[i][j] = sum[i][j - 1] + x; ///行前缀和
        }
    int ans = 0;
    for(int i = 1;i <= n; ++i)
    {
        stack<node>s;   ///单调栈
        for(int j = 1;j <= m + 1; ++j)
        {
            x = j;
            while(!s.empty() && s.top().h >= h[i][j])
            {
                x = s.top().w;
                l = x,r = j - 1;
                if(h[i][j] < s.top().h && sum[i + 1][r] - sum[i + 1][l - 1] != r - l + 1)
                    ans++;
                s.pop();
            }
            if(!h[i][j])  ///后面的不会与前面的相连
            {
                while(!s.empty()) s.pop();
                continue;
            }
            s.push(node{h[i][j],x});
        }
    }
    printf("%d\n",ans);
    return 0;
}

B题

链接:https://ac.nowcoder.com/acm/contest/888/B
来源:牛客网
 

题目描述

Gromah and LZR have entered the second level. There is a sequence a1,a2,⋯ ,an on the wall.

There is also a note board saying "the beauty value of a sequence is the number of different elements in the sequence".

LZR soon comes up with the password of this level, which is the sum of the beauty values of all successive subintervals of the sequence on the wall.

Please help them determine the password!

 

输入描述:

The first line contains one positive integer n​, denoting the length of the sequence.

The second line contains nn_{}n​ positive integers a1​,a2​,⋯,an​, denoting the sequence.

1≤ai≤n≤10^5

输出描述:

Print a non-negative integer in a single line, denoting the answer.

示例1

输入

复制

4
1 2 1 3

输出

复制

18

说明

The beauty values of subintervals [1,1],[2,2],[3,3],[4,4] are all 1​.
The beauty values of subintervals [1,2],[1,3],[2,3],[3,4] are all 2​.
The beauty values of subintervals [1,4],[2,4] are all 3​.
As a result, the sum of all beauty values are 1×4+2×4+3×2=18

总体来说这道题就是计算每个数字对几个区间有贡献,首先对于一个数字预处理出后一个与他相同的数字位置,从开始到这个位置为止,这个区间连同所有包含这个位置的子区间,都会有这个位置的贡献,加起来即可

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#include<string>
#include<cstring>
using namespace std;

typedef long long ll;
const int maxn = 1e5 + 10;
ll n,a[maxn],r[maxn],ans;
map<ll,ll>q;

int main()
{
    scanf("%lld",&n);
    for(int i = 1;i <= n; ++i)
    {
        scanf("%lld",&a[i]);
        if(q[a[i]]) r[q[a[i]]] = i - 1;
        q[a[i]] = i;
    }
    ans = 0;
    for(int i = 1;i <= n; ++i)
    {
        if(!r[i]) r[i] = n;
        ans += i * (r[i] - i + 1);
    }
    printf("%lld\n",ans);
    return 0;
}

C题

链接:https://ac.nowcoder.com/acm/contest/888/C
来源:牛客网
 

题目描述

Gromah and LZR have entered the third level. There is a blank grid of size m×mm\times mm×m, and above the grid is a word "CDMA".

In CDMA Technology, a Technology about computer network, every network node should be appointed a unique binary sequence with a fixed and the same length. Moreover, if we regard 0​ in the sequence as −1​, and regard 1​ as +1​, then these sequences should satisfy that for any two different sequences s,t​, the inner product of s,t​ should be exactly 0​.

The inner product of two sequences s,t​ with the same length n​ equals to ∑(i=1...n)siti

So, the key to the next level is to construct a grid of size m×mm\times mm×m, whose elements are all −1​ or 1​, and for any two different rows, the inner product of them should be exactly 0​.

In this problem, it is guaranteed that mm_{}m​ is a positive integer power of 2​ and there exists some solutions for input m​. If there are multiple solutions, you may print any of them.

输入描述:

Only one positive integer m​ in one line.

m∈{2^k  ∣  k=1,2,⋯ ,10}

输出描述:

Print m​ lines, each contains a sequence with length m​, whose elements should be all −1​ or 1​ satisfying that for any two different rows, the inner product of them equals 0​.
You may print multiple blank spaces between two numbers or at the end of each line, and you may print any number of blank characters at the end of whole output file.

示例1

输入

复制

2

输出

复制

1 1
1 -1

构造题,考虑如何由已知的m = 2推出m = 4,8等等

我是这样做的,m = 4的矩阵分成4块,把任选3块把m = 2的矩阵填充进去,然后剩下的那块,把m = 2的矩阵全部取其相反数在填充进去就可以了

其正确性也很好证明,对于上面的2行,因为本身的两个矩阵都满足乘积和为0,加起来也为0

后面的就要保证和前面的不重复,取反后和上面的一定不相同,却也满足乘积和为0

#include<cstdio>   //比赛的时候从4开始往8推的
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<stack>
using namespace std;

int a[5][5] = {{0,0,0,0,0},{0,-1,-1,1,1},{0,-1,1,-1,1},{0,1,-1,-1,1},{0,-1,-1,-1,-1}};
int b[2000][2000],x,m;

void unionz(int x)
{
    for(int i = 1;i <= x; ++i)
        for(int j = 1;j <= x; ++j)
        {
            b[i][j + x] = b[i + x][j + x] = b[i][j];
            b[i + x][j] = -b[i][j];
        }
}

int main()
{
    scanf("%d",&m);
    if(m == 2) printf("1 1\n1 -1\n");
    else
    {
        x = 4;
        for(int i = 1; i <= 4; ++i)
            for(int j = 1; j <= 4; ++j)
                    b[i][j] = a[i][j];
        while(m > x) unionz(x),x *= 2;
        for(int i = 1;i <= m; ++i)
            for(int j = 1;j <= m; ++j)
            {
                printf("%d",b[i][j]);
                if(j == m) printf("\n");
                    else printf(" ");
            }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值