牛客小白月赛76

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

A.猜拳游戏

AC代码:

#include
#include
#include
using namespace std;
void solve()
{
    string s;
    cin>>s;
    cout<

B.Kevin喜欢一

AC代码:

#include
#include
#include
using namespace std;
void solve()
{
    int n;
    cin>>n;
    int sum=1;
    int copy=1;
    if(sum>=n){
        cout<<0<=n){
            cout<>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
#include
#include
#include
#include
#include
using namespace std;
void solve()
{
    int n,m;
    cin>>n>>m;
    if(n-m<1||n-m>1e9||n-m<=m) cout<<-1<>t;
    while(t--)
    solve();
    return 0;
}

D.MoonLight的运算问题

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

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

#include
#include
#include
#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>x;
        res=max(res*x,res+x);
        res=res%mod;
    }
    cout<>t;
    while(t--)
    solve();
    return 0;
}

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

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

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

如图,模运算

牛客小白月赛76_第1张图片

但是呢,这就是错因所在,因为题目要我们先求出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
#include
#include
#include
#include
#include
#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>x;
        if(x<=1||res<=1) res+=x;
        else res*=x;
    }
    cout<>t;
    while(t--)
    solve();
    return 0;
}

E.括号操作序列专家

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

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

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

具体我们这样操作:

以0为基准

如果遇到左括号.sum++

如果遇到右括号,sum--

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

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

AC代码:

#include
#include
#include
#include
#include
#include
#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>t;
    while(t--)
    solve();
    return 0;
}

你可能感兴趣的:(c++,算法)