牛客小白月赛98

牛客小白月赛98

A 骰子魔术

链接:https://ac.nowcoder.com/acm/contest/85598/A
来源:牛客网

题目描述

jackle 正在给他的朋友表演一个关于骰子的魔术:
jackle 会拿出一枚骰子,骰子的表面分别写上了从 1∽500 的数字,朋友会随便说一个 1∽500 之间的点数,jackle 都能保证百分之百的掷出这个点数。
当然 jackle 有备而来,他准备了 𝑛 枚特殊的骰子,第 𝑖 枚特殊骰子,可以保证每次掷出的点数都为 𝑎𝑖 。
jackle 想问你,他能不能只拿出一枚事先准备好的特殊骰子,成功完成这次魔术。

输入描述:

第一行输入 2 个正整数 𝑛 (1≤𝑛≤1000),𝑥 (1≤𝑥≤500),分别表示 jackle 准备的特殊骰子数量,朋友说的那个点数。
第二行输入 𝑛 个正整数 𝑎𝑖 (1≤𝑎𝑖≤500),分别表示每枚特殊骰子可以掷出的点数。

输出描述:

如果 jackle 可以成功完成这次魔术,请你输出 YES;否则请你输出 NO。

示例1

输入
5 3
1 2 1 3 12
输出
YES

说明

jackle 可以选择第 4 个骰子,因为 𝑎4=𝑥=3,所以他能百分之百掷出这个朋友说出的点数,所以可以完成这次魔术。

题解

判断ai里面有没有和X相同的

#include<bits/stdc++.h>
using namespace std;

int n,x,a[1005];
int main(){
    int i,j,k;
    cin>>n>>x;
    for(i=1;i<=n;i++)
        cin>>a[i];
    for(i=1;i<=n;i++){
        if(x==a[i]){
            printf("YES\n");
            return 0;
        }
    }
    printf("NO\n");
    return 0;
}
B 最少剩几个?

链接:https://ac.nowcoder.com/acm/contest/85598/B
来源:牛客网

题目描述

给定一个长度为 𝑛 的序列 𝑎,如果当前序列长度至少为 2,那么你每次可以做如下两种操作之一:
选择 𝑖,𝑗 (𝑖≠𝑗),如果满足 𝑎𝑖+𝑎𝑗 是奇数,那么你可以同时删除
𝑎𝑖,𝑎𝑗 。
选择 𝑖,𝑗 (𝑖≠𝑗),如果满足 𝑎𝑖×𝑎𝑗 是奇数,那么你可以同时删除
𝑎𝑖,𝑎𝑗 。
你可以执行上面的操作无数次,只要你满足操作条件,jackle 想问你序列最少剩几个数?

输入描述:

第一行输入 1 个正整数 𝑛 (1≤𝑛≤105),表示序列的长度。
第二行输入 𝑛 个正整数 𝑎𝑖 (1≤𝑎𝑖≤109)。

输出描述:

输出序列最少剩几个数?

示例1

输入
1
114514
输出
1

说明

只有一个数,啥也操作不了。

示例2

输入
2
9 9
输出
0

题解

和Round 52 C很像,都是消除数字的问题,这道题应该来说更简单一些。
找规律:相乘是奇数那么必须至少有一个是奇数,相加是奇数必须是一奇一偶
然后两两消除,只需要记录奇数偶数的个数就行
偶数和偶数消不了

#include<bits/stdc++.h>
using namespace std;

int n,a[100005],s1,s2,ans;
int main()
{
    int i,j,k;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
        if(a[i]%2==0)s1++;
        else s2++;
    }
    if(s2>=s1) ans=(s2-s1)%2;
    else ans=s1-s2;
    cout<<ans<<endl;
    return 0;
}
C 两个函数

链接:https://ac.nowcoder.com/acm/contest/85598/C
来源:牛客网

题目描述

jackle 给定两个函数:

f ( x ) = a x f(x)=a x f(x)=ax
g ( x ) = { f ( x ) x = 1 ∑ i = 1 x − 1 f ( f ( i ) ) x > 1 g(x)=\left\{\begin{array}{ll}f(x) & x=1 \\ \sum_{i=1}^{x-1} f(f(i)) & x>1\end{array}\right. g(x)={f(x)i=1x1f(f(i))x=1x>1
他有 𝑄 次询问,每次给定 𝑎,𝑥,请你计算 𝑔(𝑥) mod 998244353 的结果。

输入描述:

第一行输入 1 个正整数 𝑄 (1≤𝑄≤105),表示询问次数。
接下来 𝑄 行,每行输入 2 个正整数 𝑎,𝑥 (1≤𝑎,𝑥≤109)。
输出描述:
对于每组询问,输出 𝑔(𝑥)mod  998244353 的结果。

示例1

输入
3
1 1
2 2
9982 44353
输出
1
4
572321601

题解

额,感觉智商受到侮辱。就是这个markdown 写公式,有点造孽
拿出paper推下公式就行,代码里看结果吧,太难打

#include <iostream>
using namespace std;
using LL =long long;
int main() {
    int Q, a, x;
    long long sum;
    const int mod = 998244353;
    cin >> Q;
    for (int i = 0; i < Q; i++) {
        cin >> a >> x;
        if (x == 1) {
            cout << a%mod << endl;
         
        }else{
        // 使用数学公式计算sum
        sum = 1ll*(x - 1) * x / 2;
        sum = sum%mod * a%mod * a%mod;
        cout <<sum << endl;}
    }
    return 0;
}

D 切割 01 串 2.0

链接:https://ac.nowcoder.com/acm/contest/85598/D
来源:牛客网

题目描述

jackle 在校赛的时候出过一道 “切割 01 串” 的题目,如今他又出了一道切割 01 串的题目:
给定一个长度为 𝑛 的 01 串,定义如下操作为一次 “切割”:
将长度大于 1 的字符串分割为两个非空的连续字串,记分割出来的左侧字串 𝑎 中 0 的出现次数为 𝐶0 ,右侧字串 𝑏 中 1 出现的次数为 𝐶1 ,需要满足 𝐿≤∣𝐶0−𝐶1∣≤𝑅。
你每次切割完,都会得到两个新 01 串,你可以继续选择这些已经被你切出来的 01 串做切割,只要满足切割条件。
jackle 想问你最多可以切割多少次?

输入描述:

第一行输入 3 个整数,𝑛 (1≤𝑛≤500),𝐿,𝑅 (0≤𝐿≤𝑅≤500),分别表示字符串长度,和题目中的两个参数。
第二行输入 1 个长度为 𝑛 的 01 串。

输出描述:

输出最多能切割多少次?

示例1

输入
6 2 3
011011
输出
3

说明

其中一种切割次数最多的切法如下:
第一次切割可以切:0 ∣ 11011,然后选择 11011 这个串继续做切割。
第二次切割可以切:1 ∣ 1011,然后选择 1011 这个串继续做切割。
第三次切割可以切:1 ∣ 011。

题解

区间DP
dp[l,r] 区间[l,r]的对应的答案
然后判断在区间[l,r]中是否符合条件要求累加

#include<bits/stdc++.h>
using namespace std;
int n,l,r;
char s[505];
int cnt[505][2],dp[505][505];

int main(){
    int i,j,k;
    cin>>n>>l>>r>>s+1;
    for(i=1;s[i];i++){
        for(j=0;j<2;j++)cnt[i][j]=cnt[i-1][j];
        cnt[i][s[i]-'0']++;
    }
    for(int len=1;len<=n;len++){
        for(i=1;i+len-1<=n;i++){
            for(j=i;j<i+len-1;j++){
                int c=abs((cnt[j][0]-cnt[i-1][0])-(cnt[i+len-1][1]-cnt[j][1]));
                if(c<=r&&c>=l) dp[i][i+len-1]=max(1+dp[i][j]+dp[j+1][i+len-1],dp[i][i+len-1]);
            }
        }
    }
    printf("%d",dp[1][n]);
    return 0;
}
E and xor or

链接:https://ac.nowcoder.com/acm/contest/85598/E
来源:牛客网

题目描述

给定一个长度为 𝑛 的序列 𝑎,jackle 想让你求出有多少个区间 [𝑙,𝑟] 满足如下条件:
1≤𝑙≤𝑟≤𝑛
2𝑘1≤(𝑎𝑙 & 𝑎𝑙+1 &…& 𝑎𝑟)⊕(𝑎𝑙 ∣ 𝑎𝑙+1 ∣…∣ 𝑎𝑟)<2𝑘2
其中 &,∣,⊕,分别表示按位与,按位或,按位异或。

输入描述:

第一行输入 3 个整数 𝑛 (1≤𝑛≤5×105),𝑘1,𝑘2 (0≤𝑘1<𝑘2≤109)。
第二行输入 𝑛 个整数 𝑎𝑖 (0≤𝑎𝑖≤1018)。

输出描述:

输出满足条件的区间数量。

示例1

输入
4 0 2
2 1 4 3
输出
1

说明

只有区间 [1,2] 满足条件:20≤(2 & 1)⊕(2 ∣ 1)=3<22

示例2

输入
6 0 4
7 6 7 6 7 7
输出
14
在这里插入图片描述

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,k1,k2,a[500005],l[65][500005];

signed main()
{
    cin>>n>>k1>>k2;
    for(int i=1;i<=n;i++)cin>>a[i];
    
    if(k1>=60)
    {
        cout<<0;
        return 0;
    }
    
    int len=60;//1e18的二进制数长为60
    for(int k=0;k<len;k++)//枚举位数,然后用双指针算法处理出数组l[][]
    {
        int cnt0=0,cnt1=0;//0的个数,1的个数
        for(int i=1,j=1;j<=n;j++)
        {
            int t=((a[j]>>k)&1);
            t?cnt1++:cnt0++;
            while(cnt0 && cnt1)//同时存在0和1
            {
                l[k][i]=j;
                int t=((a[i++]>>k)&1);
                t?cnt1--:cnt0--;
            }
        }
    }
    
    //符合条件的区间:f[l,r]的二进制数最高1的位数在[k1,k2-1]
    int ans=0;
    for(int i=1;i<=n;i++)//枚举左边界
    {
        int a=n+1,b=n+1;
        for(int k=k1;k<len;k++)
        {
            if(l[k][i]==0)continue;
            if(k<=k2-1)a=min(a,l[k][i]);
            else b=min(b,l[k][i]);
        }
        if(a==n+1)continue;
        ans+=max(b-a,0LL);
    }
    cout<<ans;
    
    return 0;
}
F 绝妙的手法

链接:https://ac.nowcoder.com/acm/contest/85598/F
来源:牛客网

题目描述
本题出题时想到的贪心做法是错误的,评测数据也是按照出题时的std造的,目前本题没有正确解法,不建议大家做这道题。

给定一个长度为 𝑛 的序列 𝐴,你每次可以做如下操作:
每次选择两个不同的下标 𝑖,𝑗,令 𝐴𝑖=𝐴𝑖+𝐴𝑗
jackle 想问你最少操作几次,可以使得序列中恰好有 𝑚 个正数。

输入描述:

注意本题有多组测试数据。
第一行先输入 1 个整数 𝑇(1≤𝑇≤2×105),表示数据组数。
对于每组测试数据:
第一行输入 2 个整数 𝑛,𝑚 (1≤𝑛≤2×105,0≤𝑚≤2×105)
第二行输入 𝑛 个整数 𝐴𝑖 (−1012≤𝐴𝑖≤1012)。
题目保证 ∑𝑛≤2×105

输出描述:

对于每组测试数据:
如果能通过操作,使得序列中恰好有 𝑚 个正数,请你输出最小操作次数;否则请你输出
−1。

示例1

输入
1
4 3
-1 -1 1 2
输出
1

说明

显然操作一次即可:选择 𝑖=1,𝑗=4,令 𝐴1=𝐴1+𝐴4=−1+2=1,操作完之后 𝐴1=1,那么此时序列中恰好 3 个正数。

示例2

输入
1
5 3
0 0 0 0 0
输出
-1

说明

由于所有数都是 0,所以无论怎么执行 𝐴𝑖=𝐴𝑖+𝐴𝑗 ,序列中的数都还是 0,所以一定无法操作使得序列恰好出现 3 个正数。

示例3

输入
2
4 2
-10 1 1 1
6 4
4 -2 -2 -3 2 -4
输出
1
2

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

洋洋的计算机刷题日记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值