20250815组题总结

A - A

对于一个由非负整数构成的多重集合T,我们定义:

sum(T)表示T中所有元素的总和。例如,若T={0,1,1,3},则sum(T)=0+1+1+3=5。

mex(T)指不在T中的最小非负整数。比如T={0,1,1,3}时,mex(T)=2,因为2是最小的缺失非负整数。

现给定一个大小为n的非负整数多重集合S。初始分数为0,你可以不限次数和顺序(也可不操作)执行以下两种操作:

  1. 选择子集S’⊆S,将sum(S’)加入分数,并从S中移除S’;
  2. 选择子集S’⊆S,将mex(S’)加入分数,并从S中移除S’。

求你能获得的最大分数。

找规律,因为我们可以发现,只要每次挑出一个0出来,可以比原来直接加上去多1,所以我们先对每一个0进行一次mex操作,其余的数直接sum起来就行了。

#include <bits/stdc++.h>
using namespace std;
int s[55],t[55];
int main(){
	int q;
	cin>>q;
	while(q--){
	    memset(t,0,sizeof t);
	    int n,sum=0;
	    cin>>n;
	    for(int i=1;i<=n;i++){
	        cin>>s[i];
	        t[s[i]]++;
	        sum+=s[i];
	    }
	    cout<<sum+t[0]<<endl;
	}
	return 0;
}

B - B

一家公司有 n 名员工,编号为 1 到 n。每位员工要么没有直属上级,要么只有一个直属上级(其上级必须是其他编号的员工)。员工 A 是员工 B 的上级需满足以下条件之一:

  1. A 是 B 的直属上级;
  2. B 有直属上级 C,而 A 是 C 的上级。

公司不存在管理循环,即没有员工是自己的上级。

现在公司要举办派对,需要将员工分组,要求:

  • 每位员工必须且只能属于一个小组;
  • 同一小组内不能存在上级关系(即不能有员工 A 和 B 满足 A 是 B 的上级)。

求最少需要分成多少个小组。

因为同一组不能有祖孙关系,也就是说每一组一定在同一层,哪怕不在同一颗树内,所以我们只要找到深度最深的那颗树的深度就是我们的答案。

参考:

1
2
3
4
5
6

该组数据答案为3。

#include <bits/stdc++.h>
using namespace std;
int zz[2005];//每棵树的根节点
vector<int> E[2005];
int yy[2005];//用来存储每棵树的深度
bool f[2005];
void dfs(int x,int fa,int cc,int sd){
    if(!f[sd])yy[cc]++;
    f[sd]=1;
    for(int i=0;i<E[x].size();i++){
        int v=E[x][i];
        if(v==fa)continue;
        dfs(v,x,cc,sd+1);
    }
}
int main(){
    int n,cs=0;//多少个点,多少个祖宗
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        if(x!=-1){
            E[i].push_back(x);
            E[x].push_back(i);
        }else{
            zz[++cs]=i;
        }
    }
    for(int i=1;i<=cs;i++){
        memset(f,0,sizeof f);
        dfs(zz[i],0,i,1);
    }
    int mx=0;
    for(int i=1;i<=cs;i++){
        mx=max(mx,yy[i]);
    }
    cout<<mx;
	return 0;
}

C - C

课间休息时,食堂里排着一条由n名男生女生组成的队伍。最初,孩子们按照进入食堂的顺序站好。但不久后,男生们开始因站在女生前面而感到不自在,于是每秒都会让前方的女生向前移动。

具体来说,队伍的位置编号为1到n,其中1号位置的人最先接受服务。若在x时刻,第i个位置是男生而第(i+1)个位置是女生,那么在x+1时刻,这两个位置会互换:第i个位置变为女生,第(i+1)个位置变为男生。时间以秒为单位计算。

已知初始时刻队伍的排列情况,请计算出t秒后队伍的最后状态。

模拟大水题,由于n<=50,所以我们丝毫不慌。我们用bool数组模拟男女生,经过t次更新,最终直接输出目前bool数组的状态。

#include <bits/stdc++.h>
using namespace std;
bool f[55],ff[55];//使用bool更加方便,记得输出要变成字符
int main(){
    int n,t;
    cin>>n>>t;
    for(int i=1;i<=n;i++){
        char x;
        cin>>x;
        if(x=='B'){
            f[i]=1;
        }
    }
    for(int i=1;i<=t;i++){
        ff[1]=f[1];
        for(int k=1;k<n;k++){
            ff[k+1]=f[k+1];//这么写纯属偷懒
            if(f[k]&&!f[k+1]){//看男生后面是不是女生
                swap(ff[k],ff[k+1]);
            }
        }
        for(int k=1;k<=n;k++){
            f[k]=ff[k];
        }
    }
    for(int i=1;i<=n;i++){
        if(f[i]){
            cout<<'B';
        }else{
            cout<<'G';
        }
    }
	return 0;
}

D - D

国王独自镇守棋盘。虽孤军奋战,却毫不气馁,因为他肩负着守卫王国的重任。此刻,他需要尽快从当前位置s前往t方格进行正式访问。向来注重效率的国王,希望以最少的步数完成这次移动。

这是一个国际象棋棋盘
国王的移动规则如下:每次可向任意相邻方格移动,包括横向、纵向及斜向共8个方向。具体移动指令对应为:

  • 基本方向:L(左)、R(右)、U(上)、D(下)
  • 斜向组合:LU(左上)、LD(左下)、RU(右上)、RD(右下)

也是模拟水题,直接dfs爆搜就行了,每次看走那边更近,直接走向那一边。应该不会有人打表吧……有4096种情况

#include <bits/stdc++.h>
using namespace std;
int xs,xe,ys,ye,b[30];
string fx[10]={"","U","D","L","R","LU","RU","LD","RD"};//八个方向,注意顺序
//网上,网下,王座,网友,坐上,忧伤,坐下,游侠,@一下你打出来的是啥吧!
void dfs(int x,int y){
    if(xe==x&&ye==y){//走完了
        return;
    }
    if(xe<x&&ye==y){//往上
        b[++b[0]]=1;
        dfs(x-1,y);
    }
    if(xe>x&&ye==y){//往下
        b[++b[0]]=2;
        dfs(x+1,y);
    }
    if(xe==x&&ye<y){//往左
        b[++b[0]]=3;
        dfs(x,y-1);
    }
    if(xe==x&&ye>y){//往右
        b[++b[0]]=4;
        dfs(x,y+1);
    }
    if(xe<x&&ye<y){//左上
        b[++b[0]]=5;
        dfs(x-1,y-1);
    }
    if(xe<x&&ye>y){//右上
        b[++b[0]]=6;
        dfs(x-1,y+1);
    }
    if(xe>x&&ye<y){//左下
        b[++b[0]]=7;
        dfs(x+1,y-1);
    }
    if(xe>x&&ye>y){//右下
        b[++b[0]]=8;
        dfs(x+1,y+1);
    }    
}
int main(){
    char x,y;
    cin>>x>>xs>>y>>xe;
    xs=8-xs+1;
    xe=8-xe+1;
    ys=int(x)-'a'+1;
    ye=int(y)-'a'+1;//一系列处理
    dfs(xs,ys);//出发喽
    cout<<b[0];//输出总共走了几步
    for(int i=1;i<=b[0];i++){
        cout<<endl<<fx[b[i]];
    }
	return 0;
}

E - E

你有一副包含 n 张卡牌的牌堆,从上到下依次编号为 1 到 n(顶部牌为 1,底部牌为 n)。每张牌都有一个颜色属性:第 i 张牌的颜色为 a i a_i ai

现在需要处理 q 个查询。对于第 j 个查询:

  1. 在牌堆中找出颜色为 t j t_j tj 且位置最高的牌(即索引最小的牌)
  2. 输出该牌的位置
  3. 将该牌从当前位置取出,并放置到牌堆顶部你有一副包含 n 张卡牌的牌堆,从上到下依次编号为 1 到 n(顶部牌为 1,底部牌为 n)。每张牌都有一个颜色属性:第 i 张牌的颜色为 a i a_i ai

第一行包含两个整数n和q ( 2 ≤ n ≤ 3 × 10 5 , 1 ≤ q ≤ 3 × 10 5 ) (2 ≤ n ≤ 3×10⁵,1 ≤ q ≤ 3×10⁵) 2n3×1051q3×105,分别表示牌堆中的卡牌数量和查询数量。

第二行包含n个整数 a 1 , a 2 , . . . , a n ( 1 ≤ a i ≤ 50 ) a₁, a₂, ..., a_n(1 ≤ aᵢ ≤ 50) a1,a2,...,an(1ai50),表示每张卡牌的颜色。

第三行包含q 个整数 t 1 , t 2 , . . . , t q ( 1 ≤ t j ≤ 50 ) t₁, t₂ , ..., t_q(1 ≤ tⱼ ≤ 50) t1,t2,...,tq1tj50,表示查询的颜色。题目保证所有查询的颜色都存在于牌堆中。

这题有点意思,因为n和q有3e5,所以就不能暴力,而且每次还要进行修改。

但我们看到了一个东西,1 ≤ aⱼ ≤ 50,题目故意设这么小干什么呢?当然是让我们水题做题的呀!

于是,我们可以使用一个数组来统计每个数最早出现在哪个位置,每次询问直接输出。

然后我们就要对这个数组进行更新,循环找出位于这个数之前的数,让他们的最早出现的位置++,最后再让这个数最早出现的位置变成1。

#include <bits/stdc++.h>
using namespace std;
int a[300005],b[55];
int main(){
    int n,q,mx=0;
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(!b[a[i]]){
            b[a[i]]=i;
        }
        mx=max(mx,a[i]);
    }
    while(q--){
        int x;
        cin>>x;
        cout<<b[x]<<" ";
        for(int i=1;i<=mx;i++){//i循环到50也行
            if(b[i]<b[x]){
                b[i]++;
            }
        }
        b[x]=1;
    }
	return 0;
}

F - F

弗拉德回家时,发现有人将旧恒温器的温度重新设置成了a。

该恒温器的温度只能在[l,r]范围内调节(包括端点值),且每次温度变化的绝对值必须不小于x。具体来说,当满足|a-b|≥x且l≤b≤r时,可以通过单次操作将温度从a调整到b。

给定参数l、r、x、a和b,要求计算从温度a调整到b所需的最少操作次数。若无法实现温度调整,则需要给出相应说明。

这题,嗯,额,嘶,说白了就是分支结构,详细直接看以下代码。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        long long l,r,x,a,b;//温度范围及最小温度变化值及初始温度和最终温度
        cin>>l>>r>>x>>a>>b;
        if(a>b){
            swap(a,b);
        }
        if(a<l||b>r){
//预期的温度超过了温度范围
            cout<<-1<<endl;
            continue;
        }        
        if(a==b){
//初始温度和最终温度相同
            cout<<0<<endl;
            continue;
        }
        if(b-a>=x){
//如果他们之间的距离大于等于最小温度变化值
            cout<<1<<endl;
            continue;
        }
        if(b+x<=r||a-x>=l){
//如果可以通过 先增加若干温度再减到最终温度 或 先减少若干温度再增加到最终温度
            cout<<2<<endl;
            continue;
        }
        if(a+x<=r&&b-x>=l){
//如果可以先增加若干温度再减少若干温度再增加到最终温度 或 反之
            cout<<3<<endl;
            continue;
        }
        cout<<-1<<endl;//否则还是不行
    }
	return 0;
}

发一条友善的评论吧!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值