河南萌新联赛2024第四场补题

除了AGL,要看这三题请移步。

D.简单的素数

很简单,但不能用素数筛,1e8量级跑一秒直接超时,直接暴力最简单的那种素数check就行

F.小磊的算式

也是签到,把加号之间的数字取出来就行了

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
using pii = pair<int,int>;
using tri = tuple<int,int,int>;
void solve(){
    string a;
    cin>>a;
    vector<int> pos;
    vector<ll> nums;
    for(int i = 0;i<a.size();i++) if(a[i]=='+') pos.push_back(i);
    ll res = 0;
    ll mid = 10;
    for(int i = 0;;i++){
        if(a[i]=='+'){
//             cout<<res<<endl;
            nums.push_back(res);
            break;
        }
        res = res*mid+(a[i]-'0');
    }
    int lenpos = pos.size();
    
    for(int i = 0;i<=lenpos-2;i++){
        res = 0;
        mid = 10;
        for(int j = pos[i]+1;j<=pos[i+1]-1;j++){
            res = res*mid+(a[j]-'0');
        }
        nums.push_back(res);
    }
    
    res = 0;
    mid = 10;
    for(int i = pos[lenpos-1]+1;i<a.size();i++){
        res = res*mid+(a[i]-'0');
//             mid = mid*10;
    }
//     cout<<res<<endl;
    nums.push_back(res);
    ll ans = 0;
    for(auto x : nums) ans+=x;
    sort(nums.begin(),nums.end());
    reverse(nums.begin(),nums.end());
    for(int i = 0;i<nums.size();i++){
        if(i==nums.size()-1) cout<<nums[i];
        else cout<<nums[i]<<'+';
    }
    cout<<endl<<ans<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int Text_number = 1;
    // cin>>Text_number;
    while(Text_number--) solve(); 
    return 0;
}

H.聪明且狡猾的恶魔

思维题,已知只要有百分之五十以上的选票就能通过,所以只要保证半数人有钱可拿就行,还要保证拿到钱的人得到的钱相同,那就赋值为一,所以这题就解出来了,赛时说失误有0的样例,但我还是直接过了,输入为0输出的是x+1

void solve(){
    int x,n;
    cin>>x>>n;
    int ans = 0;
    if(n==1||n==2){
        cout<<x<<endl;
        return ;
    }
    if(n%2==0){
        ans = x-n/2;
        ans++;
    }else{
        ans = x-n/2;
    }
    cout<<ans<<endl;
}

B.小雷的神奇电脑

首先说同或运算,手搓发现只要让m位为1的数字减去要做同或运算的两个数字的异或值就能得到同或,紧接着,对数组进行sort,可以证明只有相邻的两个数才可能出现同伙最大值,因为相邻的两个数拥有相同的二进制前缀的概率更大;

void solve(){
    vector<ll> a;
    int n,m;
    cin>>n>>m;
    a.resize(n+1);
    for(int i = 1;i<=n;i++) cin>>a[i];
    sort(a.begin(),a.end());
    int len = a.size();
    ll ans = 0;
    ll res = 0;
    for(int i = 0;i<=m-1;i++) res = res+(1<<i); 
    for(int i = 1;i<len-1;i++){
        ans = max(ans,res-(a[i]^a[i+1]));
    }
    cout<<ans<<endl;
}

C.岗位分配

赛时看到队友前三道签到都没写完直接把这题过了,可是本菜鸡还不会,赛后说是板子题,是插板法板子题,不会的可以移步至b站董晓算法插板法,看完就会了

const int mod = 998244353;

int a[1001];
int c[3001][3001];
int n,m;

void solve(){
    cin>>n>>m;
    ll sum = 0;
    for(int i = 1;i<=n;i++) cin>>a[i],sum+=a[i];
    for(int i = 0;i<=m+n;i++){
        c[i][0] = 1;
        for(int j = 1;j<=i;j++){
            c[i][j] = (c[i-1][j-1]*1ll + c[i-1][j])%mod;
        }
    }
    ll ans = 0;
    for(int i = sum;i<=m;i++){
        ans+=c[i-sum+n-1][n-1];
        ans%=mod;
    }
    cout<<ans<<endl;
}

E.AND

首先看题,肯定要把所有素数筛出来,怎么做到这一步,因为签到t了,所以想了20分钟也没想出来,直到最后半小时看到了时间限制为2s,刚好其中一秒把质数筛跑完,我真**啊,然后筛完之后发现,只有包含2的区间才可能AND为0,所以二分出答案就行了,没有2就输出0,有2就输出区间长度-2。(不知道为什么手搓二分过90.9%,队友用lower_bound过完了)

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

using ll =long long;
using pii = pair<int,int>;
using tri = tuple<int,int,int>;

const int N = 1e8+10;
bool st[N];//初始默认全部的数都是质数,都没有被筛,质数是false,合数是true
int primes[N];
int cnt;

void linenum(int n){
    for(int i = 2;i<=n;i++){
        if(!st[i]){//如果这个数是一个质数那么记录下来
            primes[cnt] = i;
            cnt++;
        }
        for(int j = 0;primes[j]<=n/i;j++){//遍历所有筛过的质数
            st[i*primes[j]] = true;//i*质数将该数(i*质数)筛掉
            if(i%primes[j]==0) break;//线性筛法核心,保证每个数字只被筛出一次,用最小质数来实现。
        }
    }
}

int lfind(int x){
    int l = 0;
    int r = cnt-1;
    while(l<r){
        int mid = l+r>>1;
        if(primes[mid]>=x){
            r = mid;
        }else{
            l = mid+1;
        }
    }
    
    return l;
}

int rfind(int x){
     int l = 0;
    int r = cnt-1;
    while(l<r){
        int mid = l+r+1>>1;
        if(primes[mid]<=x){
            l = mid;
        }else{
            r = mid-1;
        }
    }
    
    return l;
}

void solve(){
    int x,y;
    cin>>x>>y;
    int l = lfind(x);
    int r = rfind(y);
    cout<<r-l+1<<' ';
    if(primes[l]>2) cout<<"0"<<endl;
    else cout<<r-l-1<<endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    linenum(100000005);
    
    int Text_number = 1;
    cin>>Text_number;
    while(Text_number--) solve(); 
    return 0;
}

I.马拉松

注意到是一棵树,所以x到y之间一定只有一条路径,期间所有的边都是桥,所以只要找到x能到的点并且这个点不在x->y的路径上的点的总数ans1和y能到达的并且不在x->y路径上的点总数ans2,答案就是ans1*ans2.


void dfs(int x,int y,int num)
{
    memset(st,0,sizeof st);
    queue<int>q;
    q.push(x);
    while(q.size())
    {
        int t=q.front();
        q.pop();
        if(st[t]||t==y)    continue;
        st[t]=1;
        cnt[t]+=num;
        for(auto x : e[t])
            q.push(x);
    }
}

J.尖塔第四强的高手

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值