2019暑期组队排位总结

2019暑期组队排位总结

Wiki:戳这里
我还是习惯性在博客也开一篇总结方便看吧哈哈哈哈

2019牛客暑期多校(第一场)

problem J

题意:给你两个分数x/a,y/b,要你比较他们大小。分子范围为1e18,分母范围为1e9。

题解:直接交叉相乘会爆ll,所以先把两个数的整数部分求出来作比较,如果整数部分一样,再把分子%分母,这样两个分数交叉相乘就不会爆ll,可以比较了。

problem A

题意:两个数组定义为相等的,当且仅当从两个数组中任选一个区间[l,r],他们的最小值的下标是一样的,给你两个数组u和v,问你最大的下标p,使得1到p中任选一个区间,他们的最小值下标是一样的。

证明:假设遍历到第i个元素,也就是前i-1个元素都是符合条件的,那么我们需要考虑的新区间就是以第i个元素为右端点的所有区间,现在我们考虑以第i个元素为最小值的区间最左能延伸到哪里,如果两个数组最左能延伸到的位置,即栈大小是一样的,就说明是符合条件的。

题解:两个数组分别用一个单调递增的栈维护,当且仅当遍历到第i个元素,两个栈的size一样,ans = p,否则,直接break。

代码:戳这里

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int x[maxn],y[maxn];
 
int main()
{
   
    int n;
    while(~scanf("%d",&n))
    {
   
        for(int i=1; i<=n; i++)
        {
   
            scanf("%d",&x[i]);
        }
        for(int i=1; i<=n; i++)
        {
   
            scanf("%d",&y[i]);
        }
        stack<int> a,b;
        int ans = 1;
        for(int i=1; i<=n; i++)
        {
   
            while(!a.empty() && x[i] < a.top())
            {
   
                a.pop();
            }
            a.push(x[i]);
            while(!b.empty() && y[i] < b.top())
            {
   
                b.pop();
            }
            b.push(y[i]);
            if(a.size() != b.size())
                break;
            else
                ans = i;
        }
        printf("%d\n",ans);
    }
}

problem E

题意:一个2*(n+m)长度的只包含“A”“B”的序列,可以分解成n+m个子序列,其中有n个“AB”,m个“BA”,给你n和m,问你符合条件的序列有多少个。

题解:对于一个序列从前往后遍历过去,遇到一个“A”,肯定会优先把它当成“AB”的“A”,再考虑它是“BA”的“A”,遇到一个“B”同理。那么我们可以有dp[x][y]表示一共有x个“A”,y个“B”,当x或y至少有一个为0,此时方案数只有1。根据之前的贪心策略,任一时刻不同时满足y-x<=m和x-y<=n的话,方案数为0。这样,一个记忆化搜索的dp就很好写出来了。

代码:戳这里

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 2005;
const int mod = 1e9+7;
int n,m;
ll dp[maxn][maxn];

ll solve(int x,int y)
{
   
    if(y - x > m || x - y > n)
        return 0;
    if(x == 0 || y == 0)
        return 1;
    if(dp[x][y])
        return dp[x][y];
    dp[x][y] = solve(x-1,y) + solve(x,y-1);
    dp[x][y] %= mod;
    return dp[x][y];
}

int main()
{
   
    while(~scanf("%d%d",&n,&m))
    {
   
        for(int i=0; i<=n+m; i++)
        {
   
            for(int j=0; j<=n+m; j++)
            {
   
                dp[i][j] = 0;
            }
        }
        printf("%lld\n",solve(n+m,n+m));
    }
}

2019牛客暑期多校(第二场)

problem F

题意:给定一个N*N矩阵,令第i行j列为a[i][j],在此可理解为i和j的价值。题目要求把1–>N人分成两组,且当i和j不同组时,价值生效,否则价值为0。求分组后的最大总价值。 !!! 1<=N<=14 !!!

题解:范围不大,可暴力。 dfs模拟分组。对于当前的i,若数组A人数不够,进A组,并更新当前总价值(即加上i和B组所有人的价值)进入下一次dfs。对于B组操作也一样。

problem H

题意:给你一个只包含0和1的n×m大小的矩阵,问你第二大的全为1的矩形有多大。(不严格第二大)

题解:每个矩阵的大小由长和宽决定,矩形的长对应原矩阵中每一行最多有多少个元素,他们向上扩展的连续“1”的数量一样,矩形的宽对应向上扩展的连续“1”的数量。我们从第一行开始枚举,一开始先更新该行所有元素向上扩展最多有多少个连续“1”,设为c[j]数组,然后用一个单调递增的栈维护该行的c[j]数组,找出该行每个元素以自己为最小值,向左向右分别最远扩展到哪里,这里就有l[i],r[i]数组,此时最大的矩形面积应为(r[i]-l[i]+1)* c[j],第二小的值是max((r[i]-l[i])* c[j],(r[i]-l[i]+1) * (c[j] - 1)),然后不断更新最大值和第二大值,最后的第二大值就是答案。

代码:https://pastebin.ubuntu.com/p/BHfz5g4sPz/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
const int maxn = 1005;
char a[maxn][maxn];
int c[maxn],l[maxn],r[maxn];
 
void update(int &mx,int &mmx,int x)
{
   
    if(x <= mmx)
        return;
    if(x <= mx)
    {
   
        mmx = x;
        return;
    }
    mmx = mx;
    mx = x;
}
 
int main()
{
   
    int n,m;
    scanf("%d%d",&n,&m);
    int mx = 0,mmx = 0;
    for(int i=
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值