牛客小白月赛51

目录

A 选择题

B 填空题

C 零一题 

D 操作题

F 平均值


A 选择题

选择题

思路:略

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

int T;

void solve()
{
    int n;
    scanf("%d", &n);
    if(n%2) cout << n-2 << endl;
    else cout << n-1 << endl;
}

int main()
{

    solve();

    return 0;
}

B 填空题

填空题

思路:特判 a[0] ,然后判断其他的 i ,若为a[i] 不等于 0 ,则判断与前一个数的关系;若等于 0 ,则令其等于 前一个数 + 1;

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

int T;

void solve()
{
    int n;
    scanf("%d", &n);
    LL sum = 0;
    int a[N], x;
    for(int i = 0; i < n; i ++ )
        scanf("%d", &a[i]);

    if( a[0] == 0 )
        a[0] = 1;

    for(int i = 0; i < n; i ++ )
    {
        if(a[i] != 0)
        {
            if( i && a[i] <= a[i-1])
            {
                puts("-1");
                return ;
            }
        }
        else a[i] = a[i-1] + 1;
        
        sum += a[i];

    }

    cout << sum << endl;
}

int main()
{
    solve();

    return 0;
}

C 零一题 

零一题

思路:剩余的 x 个数一定由 01 交错排列,则答案不成立条件有两个,1.a 或 b 的长度不够 x/2

2. a 或 b 减去 x/2 后,剩余的长度无法消去,即剩余为奇数的长度。若都满足,正常输出即可,先输出可以消去的部分,再输出不能消去的部分

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

int T;

void solve()
{
    int a, b, x;
    scanf("%d%d%d", &a, &b, &x);
    LL sum = 0;

    string s;

    if( a < x/2 || b < x/2 )
    {
        puts("-1");
        return;
    }

    int ta = a - x/2;
    int tb = b - x/2;

    if( ta % 2 || tb % 2  )
    {
        puts("-1");
        return;
    }

    int aa = 0, bb = 0;
    while(s.size() < a + b - x)
    {
        if(aa < ta) aa ++, s += "0";
        if(aa < ta) aa ++, s += "0";
        if(bb < tb) bb ++, s += "1";
        if(bb < tb) bb ++, s += "1";
    }

    while(s.size() < a + b)
    {
        if(aa < a) aa ++, s += "0";
        if(bb < b) bb ++, s += "1";
    }

    cout << s << endl;

}

int main()
{
    solve();

    return 0;
}

D 操作题

操作题

思路:将 n 化为 x 进制,然后将 b 变为对应的基数,加到 a 上即可

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

int T;

void solve()
{
    int n, x;
    scanf("%d%d", &n, &x);

    int res = 0;
    int a[N], cnt = 0;
    while(n)
    {
        int t = n%x;
        a[cnt ++] = t;
        res += t;
        n /= x;
    }

    cout << res + cnt << endl;

    int b = 1;
    for(int i = 0; i < cnt; i ++ )
    {
        while( a[i] -- )
        {
            printf("1 a\n");
        }

        b *= x;
        printf("2 b\n");
    }
}

int main()
{
    scanf("%d", &T);

    while(T -- )
        solve();

    return 0;
}

F 平均值

思路:枚举区间长度即可,前缀和 + 算贡献(从其他大佬那学的,tql,)

更好理解的代码:

即、前缀和的前缀和,以下为每个区间长度下子序列的表示,每个方格表示本位置的元素+1

设表示对应区间长度总和的  q j [ i ]

我们先画出前缀和的前缀和是什么样子? 

设 前缀和数组为 s[N],前缀的前缀和数组 p[N] 

即,

 求每个区间长度总和的数组 qj[i]

qj[i] = p[n] - p[i-1] - p[n-i]

qj[1] = p[n] - p[1-1] - p[n-1] 

qj[2] = p[n] - p[2-1] - p[n-2]

qj[3] = p[n] - p[3-1] - p[n-3]

qj[4] = p[n] - p[4-1] - p[n-4]

qj[5] = p[n] - p[5-1] - p[n-5]

分别画图表示为:

表示为蓝色部分为 qj[1],绿色部分为第一个p[i-1] ,红色部分为 p[n-i],如下图表示

qj[1]:

 

qj[2]:

 qj[3]:

qj[4]: 

qj[5]:

 

与上图区间的分析完全吻合,所以该方法正确,

:(本人较菜,不会证明此方法,只能写个例子了,若大佬知道如何证明,评论区回复一下,本人会认真学习,并将此博客补充完整)

核心代码如下


for(int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);   // 原数组
for(int i = 1; i <= n; i ++ ) s[i] = s[i-1] + a[i]; // 前缀和数组
for(int i = 1; i <= n; i ++ ) p[i] = p[i-1] + s[i]; // 前缀和的前缀和数组
    
//计算:
int res = 0;
for(int i = 1; i <= n; i ++ )
    res += p[n] - p[i-1] - p[n-i];

AC代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10, mod = 1e9 + 7;

int T;
LL s[N], p[N];

int qmi(int a, int k)
{
    int res = 1;
    while(k)
    {
        if(k & 1) res = (LL)res*a % mod;
        k >>= 1;
        a = (LL)a*a%mod;
    }
    return res;
}

void solve()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++ )
        scanf("%lld", &s[i]), s[i] = (s[i-1] + s[i])%mod;
    for(int i = 1; i <= n; i ++ )
        p[i] = (p[i-1] + s[i]) % mod;

    LL res = 0;
    LL sum = 0;
    for(int i = 1; i <= n; i ++ )
        // 注意减去一个数 要 +mod%mod,再乘逆元
        res += ((p[n] - p[i-1] + mod)%mod - p[n-i] + mod)%mod * (qmi(i, mod-2)%mod)%mod;

    cout << res << endl;

}

int main()
{
    solve();

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AC自动寄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值