【题目记录】——2021牛客暑期多校训练营5


题目集地址 2021牛客暑期多校训练营5
这次题目集做的有点差,只做出了H题

B Boxes 数学 概率

题目地址【B Boxes
题意:
思路:两种情况第一种情况就是不问,即 Σ w [ i ] \Sigma w[i] Σw[i]​。
第二种情况需要询问,先加上C。之后枚举需要问几个才能确定,答案为 C + Σ p r e [ i ] ∗ ( 1 2 ) n − i C+\Sigma pre[i]*(\frac{1}{2})^{n-i} C+Σpre[i](21)ni取最小值输出即可。
AC代码:

#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5 + 10;
double w[MAXN], C, pre[MAXN];
int n;
int main()
{
    scanf("%d%lf", &n, &C);
    for (int i = 1; i <= n; ++i)
        scanf("%lf", &w[i]);
    std::sort(w + 1, w + 1 + n);
    for (int i = 1; i <= n; ++i)
        pre[i] = pre[i - 1] + w[i];
    double p = 0.5, ans = C;
    for (int i = n - 1; i >= 1; --i, p *= 0.5)
        ans += p * pre[i];
    printf("%.10lf\n", std::min(ans, pre[n]));
    return 0;
}

D double strings 思维,模拟

题目地址【D double strings
题意:给定两个字符串,从各自中选择一个长度相同的子串,找好的方案的个数,好的方案的构成是“一段相同的前缀+一个不同字符(a比b小)+长度相同的任意后缀”。
思路: d p 1 [ i ] [ j ] dp1[i][j] dp1[i][j]:A串前i个字母与B串前j个字母的等长公共子序列个数(包括空串)
d p 1 [ i ] [ j ] = d p 1 [ i − 1 ] [ j ] + d p 1 [ i ] [ j − 1 ] − d p 1 [ i − 1 ] [ j − 1 ] [ A [ i ] ≠ B [ j ] ] dp1[i][j]=dp1[i-1][j]+dp1[i][j-1]-dp1[i-1][j-1][A[i]\not =B[j]] dp1[i][j]=dp1[i1][j]+dp1[i][j1]dp1[i1][j1][A[i]=B[j]]
d p 2 [ i ] [ j ] dp2[i][j] dp2[i][j]:A串前i个字母与B串前j个字母中选择等长的公共子序列并满足A串的子序列字典序小于B串子序列字典序的子序列个数
d p 2 [ i ] [ j ] = d p 2 [ i − 1 ] [ j ] + d p 2 [ i ] [ j − 1 ] + d p 1 [ i − 1 ] [ j − 1 ] [ A [ i ] < B [ j ] ] dp2[i][j]=dp2[i-1][j]+dp2[i][j-1]+dp1[i-1][j-1][A[i]<B[j]] dp2[i][j]=dp2[i1][j]+dp2[i][j1]+dp1[i1][j1][A[i]<B[j]]
转移即可。注意dp1的初始化。
AC代码:

#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 5e3 + 10, MOD = 1e9 + 7;
int dp1[MAXN][MAXN], dp2[MAXN][MAXN];
char a[MAXN], b[MAXN];
int main()
{
    scanf("%s%s", a + 1, b + 1);
    int n = strlen(a + 1), m = strlen(b + 1);
    for (int i = 0; i <= m; ++i)
        dp1[0][i] = 1;
    for (int i = 0; i <= n; ++i)
        dp1[i][0] = 1;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
        {
            dp1[i][j] = ((dp1[i - 1][j] + dp1[i][j - 1] - dp1[i - 1][j - 1]) % MOD + MOD) % MOD;
            if (a[i] == b[j]) dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % MOD;
        }
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
        {
            dp2[i][j] = (dp2[i - 1][j] + dp2[i][j - 1]) % MOD;
            if (a[i] < b[j]) dp2[i][j] = (dp2[i][j] + dp1[i - 1][j - 1]) % MOD;
        }
    printf("%d\n", dp2[n][m]);
    return 0;
}

H Holding Two 思维

题目地址H Holding Two
题意:输出一个nm大小的01矩阵,满足条件每行连续3个每列连续3个或者每一斜着的连续三个元素不完全相同,问满足条件的矩阵是否存在,存在则输出,否则输出-1;
思路:经过思考发现不可能不存在这样的矩阵,因为构造一个很大的矩阵例如110011001100…第二行001100110011…第三行又重复第一行如此循环,这个矩阵中随意挑一个n
m的矩阵都满足条件。
AC代码:

#include <bits/stdc++.h>

using namespace std;

int f[1001][1001];
int main()
{
	cin.sync_with_stdio(0);
	cin.tie(0);
    for(int i = 1;i <= 1000;i++)
    {
        for(int j = 1;j <= 500;j++)
        {
            if(i&1)
            {
                if(j&1)
                {
                    f[i][2*j-1] = 1;
                    f[i][2*j] = 1;
                }
                else
                {
                    f[i][2*j-1] = 0;
                    f[i][2*j] = 0;
                }
            }
            else
            {
                if(j&1)
                {
                    f[i][2*j-1] = 0;
                    f[i][2*j] = 0;
                }
                else
                {
                    f[i][2*j-1] = 1;
                    f[i][2*j] = 1;
                }
            }
        }
    }
    int n,m;
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            cout << f[i][j];
        }
        cout << endl;
    }
    return 0;
}

K King of Range 队列模拟,思维

题意:给定一个长为n的序列和m次询问,每次询问给定一个k值,问有多少个区间的范围大于k,范围指的是区间最大值和最小值的差。
思路:一个线性的做法:注意到因为区间端点都是单调的,所以可以维护两个单调队列,其中一个递增序列,队首维护最小值,一个递减序列,队首维护最大值,每次弹出两个队列中队首靠前的一个,直到极差 ≤ k。那么就可以在均摊 O(1) 的时间内求 Ri 了。
AC代码:

/*
** Author:skj
** Time:2021-7-31
** function:K
*/
#include <bits/stdc++.h>
#define maxn int(1e5+2)
#define ll long long
using namespace std;
int a[maxn];
int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	cin.sync_with_stdio(0);
	cin.tie(0);
    int n, m;
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
    {
        cin >> a[i];
    }
    ll ans = 0;

    while(m--)
    {
        deque<int> maxi,mini;//maxi队首为最大值,单调递减序列。mini队首为最小值,单调递增序列。
        int k;
        cin >> k;
        int j = 1;
        for(int i = 1;i <= n;i++)
        {
            while(!maxi.empty()&&a[maxi.back()]<a[i])//维护递减序列
            {
                maxi.pop_back();
            }
            maxi.push_back(i);
            while(!mini.empty()&&a[mini.back()]>a[i])//维护递增序列
            {
                mini.pop_back();
            }
            mini.push_back(i);
            while(a[maxi.front()]-a[mini.front()]>k)
            {
                while(j <= min(maxi.front(),mini.front()))//j相当于区间左端点,右移。
                {
                    ans += (ll)n + 1 - max(maxi.front(),mini.front());
                    j++;
                }
                if(maxi.front()==j-1)
                {
                    maxi.pop_front();
                }
                if(mini.front()==j-1)
                {
                    mini.pop_front();
                }
            }
        }
        cout << ans << endl;
        ans = 0;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值