牛客小白月赛76

文章提供了几道算法编程问题的解决方案,包括猜拳游戏、Kevin的喜好、A加B模运算问题、MoonLight的运算问题和括号操作序列。这些问题涉及到了模运算、最大值计算和括号匹配等算法思想,解答过程中强调了理解题意、寻找规律和优化算法的重要性。
摘要由CSDN通过智能技术生成

牛客小白月赛76_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

A.猜拳游戏

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void solve()
{
    string s;
    cin>>s;
    cout<<s<<endl;
}
signed main()
{
    solve();
    return 0;
}

B.Kevin喜欢一

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void solve()
{
    int n;
    cin>>n;
    int sum=1;
    int copy=1;
    if(sum>=n){
        cout<<0<<endl;
        return;
    }
    for(int i=1;;i++){
        sum+=copy;
        copy=sum;
        if(sum>=n){
            cout<<i<<endl;
            return;
        }
    }
}
signed main()
{
    int t;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

C.A加B,A模B

首先呢,如果对于k,从0一个一个找,有t(2e5)个样例,一定会超时,于是果断放弃这种方法,寻求其它方法,此时千万不要死磕,一直执着于此,一直苦恼

有2e5个样例,会想到每个样例可能是O(1),大概率是个思维题,应该有某些规律,应该重新读题面,从中寻找隐藏信息

可以从a mod b = m中提取一些信息,可得m小于b

a=n-b==>a=k*b+m(k>=0)

n-b=k*b+m==>n-m=(k+1)*b>0

b>m

n-m是个定值,要想b>m,能够成立,那么b要尽可能大,那么(k+1)尽可能小,所以k取0,此时b做到最大如果都不满足b>m,那么就不可能满足了,就输出-1

b就取n-m,a取m

b的范围是[1,1e9],以及b>=m如果不在这个范围内,那么b不合法,则输出-1,否则输出m和n-m

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<set>
using namespace std;
void solve()
{
    int n,m;
    cin>>n>>m;
    if(n-m<1||n-m>1e9||n-m<=m) cout<<-1<<endl;
    else cout<<m<<" "<<n-m<<endl;
}
signed main()
{
    int t;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

D.MoonLight的运算问题

首先,要知道这不会超时的,虽然t范围为1e5,n范围为2e5,但是数据保证了n的总和不超过2e5

我一开始的代码是这样写的:

#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=2e5+10,mod=998244353;
int f[N];
void solve()
{
    int n;
    cin>>n;
    int res=0;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        res=max(res*x,res+x);
        res=res%mod;
    }
    cout<<res%mod<<endl;
}
signed main()
{
    int t;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

然后答案错误,用例通过率仅为44.44%,现在来分析一下这样写为什么是错的

首先,题目要求求出x的最大值,然后对998244353取模

但要注意x后面越来越大,可能会爆long long,所以需要一边操作,一边取模

如图,模运算

但是呢,这就是错因所在,因为题目要我们先求出x的最大值,然后再取模,而我们为了防止爆long long,必须一边操作一边取模,每次res都会取模,如果这样写的话,res=max(res*x,res+x),在比较谁大之前,前面一次循环res是取模了的,可能原本真实的res值是res*x大于res+x的,但是取模后的res值可能就是res*x小于res+x了,这样就出错了,所以我们应该依据真实的res值来选择执行哪个操作才能更大

首先,如果x小于等于1的话,不管res的真实值是多少,都应该执行res+=x,注意x大于等于0,所以res的真实值肯定是在不断变大的(当然,我们要选择最优的策略,可不能自己作死选择res*=0),那么当res一旦大于1之后,res的真实值就不会再减小了(而取模之后有可能减小的),此时如果x>1都执行res*=x操作

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<set>
#define int long long
#define endl '\n'
using namespace std;
const int mod=998244353;
int n;
void solve()
{
    cin>>n;
    int res=0;
    bool flag=true;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        if(x<=1||res<=1) res+=x;
        else res*=x;
    }
    cout<<res<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

E.括号操作序列专家

首先分别统计左括号和右括号的个数,如果个数不相等,肯定不能使括号序列变合法,直接输出-1

否则肯定有办法使得括号序列变合法

对于每一个左括号,一直往左移动,去匹配最左边的没有被匹配的右括号

具体我们这样操作:

以0为基准

如果遇到左括号.sum++

如果遇到右括号,sum--

sum如果小于0的话,sum的绝对值即表示此时左边还有多少个右括号没有被匹配

如果遇到左括号,并且sum小于0的话,那么说明该左括号的左边还有sum的绝对值个右括号还未被匹配,那么该左括号就需要往左移动(和左边相邻的交换)sum的绝对值次

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<set>
#define int long long
#define endl '\n'
using namespace std;
int n;
void solve()
{
    cin>>n;
    string s;
    cin>>s;
    int cnt=0;
    for(int i=0;i<s.size();i++){
        if(s[i]=='(') cnt++;//数一共有几个左括号
    }
    //特判,首先要保证左括号的个数和右括号的个数相同
    if(cnt*2!=n){
        cout<<-1<<endl;
        return;
    }
    int res=0;
    int sum=0;
    for(int i=0;i<s.size();i++){
        if(s[i]=='(') {
            if(sum<0) res-=sum;
            sum++;
        }
        else sum--;
    }
    cout<<res<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值