当前位置:   article > 正文

2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)_caip比赛

caip比赛

传送门

RC-u1 睿抗,启动!

题目

你被委托开发一个用于睿抗机器人开发者大赛CAIP-编程技能赛的管理系统,这个管理系统需要一些账号名和密码,你需要按照规则根据账号生成对应的密码,具体规则是:

  1. 将当前操作的字符串初始化为提供的账号名。
  2. 每次生成会规定一个生成轮次 N
  3. 对于每一轮次,按顺序执行以下操作:
  • 对于当前操作的字符串,将所有大写字母替换为后一个字母;如将 A 替换为 B,B 替换为 C,以此类推。特别地,将 Z 替换为 A。对于所有小写字母,将其替换为前一个字母,如将 z 替换为 y,以此类推。特别地,将 a 替换为 z。
  • 对于完成上一步后的字符串,如果连续出现了至少三个大写字母(不一定要相同),则将这些连续的大写字母全部改为小写字母;对于连续出现了至少三个小写字母(不一定要相同),则将这些连续的小写字母全部改为大写字母。注意修改不在原地进行,即修改结果不影响本次步骤中对于连续的判定。

现在给定账号名以及轮次,请你生成对应的密码。

思路

按照题意操作,改变字母大小写时,可以先把所有替换字母存入map中,找连续字母的时候用while循环。如果S为yourname,随便改一个字符串

代码

#include<bits/stdc++.h>
using namespace std;
unordered_map<char,char>mp;
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n;
	string e;
	cin>>n>>e;
	if(e=="yourname")e="zhenhao";
	for(int i=0;i<25;i++)mp['A'+i]='B'+i,mp['b'+i]='a'+i;
	mp['Z']='A';
	mp['a']='z';
	string s=e;
	int m=s.size();
	while(n--){
		for(int i=0;i<m;i++){
			if((s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z'))
			    s[i]=mp[s[i]];
		}
		for(int i=0;i<m;i++){
			int j=i;
			while(s[j]>='a'&&s[j]<='z'){
				if(j-i+1==3)
					for(int k=i;k<=j;k++)s[k]=toupper(s[k]);
				else if(j-i+1>3)s[j]=toupper(s[j]);
				j++;
			}
			if(j-i>=3){
				i=j-1;
				continue;
			}
			j=i;
			while(s[j]>='A'&&s[j]<='Z'){
				if(j-i+1==3)
					for(int k=i;k<=j;k++)s[k]=tolower(s[k]);
				else if(j-i+1>3)s[j]=tolower(s[j]);
				j++;
			}
			if(j-i>=3)i=j-1;
		}
	}
	cout<<e<<'\n'<<s;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

RC-u2 桌游猜谜

题目

小 C 和他的朋友一起玩一个桌游。游戏开始的时候,一共有 6 种不同颜色的卡牌,每种颜色有 8 张卡牌,其中一面写着 1 到 8 的数字,每种颜色的每个数字的卡牌只有一张。每位玩家需要从每种颜色的卡牌中抽取一张,并将卡牌摆放在自己的面前,卡牌上的数字朝外,所有玩家坐成一圈,这样所有玩家能看见其他玩家卡牌上的颜色及数字,也能看见自己的卡牌的颜色,但看不到自己的卡牌的数字。

游戏会进行若干轮,每次轮到某位玩家的时候,玩家可以选择三种不同的颜色,再选择一个范围 [L,R],询问一次其他玩家,自己对应的三种颜色的卡牌的数字之和是不是在范围内。其他玩家可以如实地回答“是”或“不是”。在游戏最后玩家需要猜测出自己卡牌上的数字是什么。

为了提高自己的游戏水平,小 C 决定考虑一个简化的问题:现在游戏刚刚开始,小 C 第一个进行询问。不难发现,进行询问后,小 C 可以根据回答排除一些自己卡牌上的数字的不可能的情况。例如选择红色、黄色、蓝色三种颜色的卡牌,询问三种颜色卡牌上的数字和的范围是否为 [5,8],假设回答是“是”,那么显然不可能出现红色卡牌数字为 2、黄色卡牌数字为3、蓝色卡牌数字为 4 的情况。

进一步地,对于一个询问,假设其他玩家给出的回答为“是”的时候可以排除的自己卡牌数字的可能方案数为 K1,给出的回答为“不是”的时候可以排除的可能方案数为 K2。小 C 自然希望自己的询问能够在不同的情况下尽可能排除更多的情况,因此小 C 希望自己的询问能够最大化 Min(K1,K2) 的值。

请你求出在询问达到以上要求的情况下,小 C 卡牌数字剩余的可能方案数为多少。

思路

因为N最多为7,T最多为5,卡牌范围1到8,所以完全可以枚举所有可能情况。题目要求最大化MIN(K1,K2)的同时,输出最多的可能值,那么就是输出MAX(K1,K2)*pow(8-n,3),其中pow(8-n,3)就是其它三张牌的可能值

代码

#include<bits/stdc++.h>
using namespace std;
int b[10][10];
pair<int,int>ans;
pair<int,int>tmp;

void dfs(int x1,int x2,int x3,int cnt,int l,int r,int sum){
    if(cnt==4){
        if(sum>=l&&sum<=r)ans.first++;
        else ans.second++;
        return;
    }
    int t=-1;
    if(cnt==1)t=x1;
    else if(cnt==2)t=x2;
    else t=x3;
    for(int i=1;i<=8;i++){
        if(b[t][i])continue;
        dfs(x1,x2,x3,cnt+1,l,r,sum+i);
    }
}

void check(){
    if(min(tmp.first,tmp.second)<min(ans.first,ans.second)){
        tmp=ans;
    }
    else if(min(tmp.first,tmp.second)==min(ans.first,ans.second)){
        if(abs(tmp.first-tmp.second)<abs(ans.first-ans.second))
            tmp=ans;
    }
}

void solve(){
    int n;
    cin>>n;
    tmp={0,0};
    memset(b,0,sizeof b);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=6;j++){
            int x;
            cin>>x;
            b[j][x]=1;
        }
    }
    for(int i=1;i<=6;i++){
        for(int j=i+1;j<=6;j++){
            for(int k=j+1;k<=6;k++){
                for(int l=3;l<=24;l++){
                    for(int r=l;r<=24;r++){
                        ans={0,0};
                        dfs(i,j,k,1,l,r,0);
                        check();
                    }
                }
            }
        }
    }
    cout<<max(tmp.first,tmp.second)*pow(8-n,3)<<'\n';
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

RC-u3 兰州拉面派餐系统

题目

lamian.jpg

兰州拉面是著名美食,其煮面很有讲究,不同种类的面需要煮不同的时长。拉面馆的煮面师傅的规则很简单,只要手头有煮面篮子是空闲的,就把下一份客单指定的面放到空闲篮子里煮;如果空闲的篮子不止一个,那么先放到其中编号最小的篮子里煮;如果没有篮子是空闲的,就等待。一个篮子里的面煮够了时间,师傅要准时捞出来放到该客单对应的碗里,招呼服务员端给客人;如果有多个篮子里的面同时到了捞取时间,师傅会同时捞起,但要本着先到先得的原则,按下单顺序招呼送餐。

在生意火爆的拉面馆里,煮面师傅需要很强的记忆力和计时能力,才能面对源源不断的客单,同时照顾一大堆煮面篮子而不出错。如果面的品种不太多,篮子也不太多,那一位拉面师傅的大脑还是能应对的。但如果我们有上千种面、上万只煮面篮、数十万客单呢…… 这就需要请你帮忙,写个派餐系统来完成这个任务了。

思路

两个要求,一是如果有多个空篮子,放编号最小的篮子里煮;二是如果有多个篮子同时完成,先给编号小的客人

那就设两个优先队列,一个排序出篮时间和客人编号、一个排序篮子编号

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=1e4+5;
int a[N];       //记录每种面时间
int b[M];       //记录每个锅用了几次

struct node{
    int numb;       //顾客编号  
    int id;         //锅编号
    int time;       //时间
    bool operator<(const node&x)const{
        if(time==x.time)return numb>x.numb;
        return time>x.time;
    }
};

priority_queue<node>q;
priority_queue<int,vector<int>,greater<int>>p;  //存空锅

bool flag;
void print(node t){
    if(flag)cout<<" ";
    flag=true;
    cout<<t.numb<<':'<<t.time;
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m,l;
    cin>>n>>m>>l;
    for(int i=1;i<=n;i++)cin>>a[i];
    int tot=0,x;
    int TIME=0;     //记录当前时间
    for(int i=1;i<=l;i++){
        cin>>x;
        if(tot<m){
            q.push({i,++tot,TIME+a[x]});
            b[tot]++;
            continue;
        }
        if(!p.empty()){		//如果有篮子是空的
            auto t=p.top();
            p.pop();
            q.push({i,t,TIME+a[x]});
            b[t]++;
            continue;
        }
        if(q.size()>1){     //找同一时间出锅
            auto now1=q.top();
            q.pop();
            auto now2=q.top();
            if(now1.time!=now2.time)q.push(now1);
            else{
                q.pop();
                TIME=now1.time;
                print(now1);
                print(now2);
                p.push(now1.id);
                p.push(now2.id);
                while(!q.empty()){
                    auto now3=q.top();
                    if(now3.time!=TIME)break;
                    q.pop();
                    print(now3);
                    p.push(now3.id);
                }
            }
        }
        if(!p.empty()){		//如果有篮子是空的
            auto t=p.top();
            p.pop();
            q.push({i,t,TIME+a[x]});
            b[t]++;
        }
        else{
            auto t=q.top();
            q.pop();
            TIME=t.time;
            print(t);
            q.push({i,t.id,TIME+a[x]});
            b[t.id]++;
        }
    }
    while(!q.empty()){
        auto t=q.top();
        q.pop();
        print(t);
    }
    cout<<'\n';
    for(int i=1;i<=m;i++)cout<<b[i]<<("%c",i==m?'\n':' ');
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

RC-u4 拆积木

题目

cjm.png

给定一个由带编号的积木搭成的长方体。其中每块积木的厚度都一样,由若干个单位边长的相邻方块组成(相邻是指两个方块有一面重合)。现在要求将这个长方体中的积木一块一块拆掉。每块积木只能从顶端取出,并且取出时不能移动还在长方体中的其它积木。请你给出一个拆积木的顺序。当然这种顺序可能是不唯一的,我们规定当有多种选择时,总是取出编号最小的那个。

思路

拓扑排序,将每个上行的编号与下行编号设路径

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=1e6+5;
int mp[N][N],cnt;
int b[M];       //记录被覆盖的数量
bool vis[M];
int to[M],from[M],head[M],idx;

void add(int u,int v){
    to[idx]=v,from[idx]=head[u],head[u]=idx++;
}
priority_queue<int,vector<int>,greater<int>>q;

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m;
    cin>>n>>m;
    memset(head,-1,sizeof head);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>mp[i][j];
            if(!vis[mp[i][j]]){
                vis[mp[i][j]]=true;
                cnt++;      //记录编号数量
            }
            if(i!=1&&mp[i][j]!=mp[i-1][j]){
                add(mp[i-1][j],mp[i][j]);
                b[mp[i][j]]++;
            }
        }
    }
    memset(vis,false,sizeof vis);
    for(int i=1;i<=m;i++){
        if(b[mp[1][i]])continue;
        if(vis[mp[1][i]])continue;
        vis[mp[1][i]]=true;
        q.push(mp[1][i]);
    }
    if(q.empty()){
        cout<<"Impossible";
        return 0;
    }
    int tot=0;
    while(!q.empty()){
        auto now=q.top();
        q.pop();
        if(tot++)cout<<' ';
        cout<<now;
        bool flag=true;
        for(int i=head[now];i!=-1;i=from[i]){
            int j=to[i];
            if(--b[j]==0){
                flag=false;
                q.push(j);
            }
        }
        if(tot==cnt)break;
        if(q.empty()&&flag){
            cout<<" Impossible\n";
            return 0;
        }
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

RC-u5 栈与数组

题目

现在有两个大小分别为 C1 和 C2 的栈,以及一个固定长度的数组,数组的每个位置一开始都是空的。只要数组仍然有空间,每次你可以从任意一个栈顶取出一个数字放置在数组的任意空位,然后判断数组里是否有 K 个相同的数字,如果有的话,那么你可以从数组里删除这 K 个数字,删除后的空间可以继续用于放置其他数字。

请问如果要将两个栈全部清空,数组的长度至少是多少?

思路

dp[ i ] [ j ]第一个存栈当前容量,第二个存最大使用过的容量,然后每到一个dp[ i ] [ j ] ,它可能是从C1中取出一个新数字、也可能是从C2中取出一个新数字,所以要判断新数字能不能删除要从两个方面比较。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=2e3+5;
int a1[N],a2[N];
int pre1[M],pre2[M];
pair<int,int>dp[N][N];

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n,m,k;
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++)cin>>a1[i];
        for(int i=1;i<=m;i++)cin>>a2[i];
        memset(dp,0x3f3f3f3f,sizeof dp);
        memset(pre1,0,sizeof pre1);
        dp[0][1]=dp[1][0]={1,1};
        for(int i=1;i<=n;i++){
            for(int j=0;j<M;j++)pre2[j]=0;
            for(int j=1;j<=m;j++){
                int val1=1,val2=1;
                if((pre1[a1[i]]+pre2[a1[i]]+1+(a1[i]==a2[j]))%k==0)val1-=k;
                if((pre1[a2[j]]+pre2[a2[j]]+1+(a1[i]==a2[j]))%k==0)val2-=k;
                int t1=max(dp[i-1][j].second,dp[i-1][j].first+1);
                int t2=max(dp[i][j-1].second,dp[i][j-1].first+1);
                if(t1!=t2){
                    if(t1<t2)
                        dp[i][j]={dp[i-1][j].first+val1,t1};
                    else
                        dp[i][j]={dp[i][j-1].first+val2,t2};
                }
                else{
                    int tmp=min(dp[i-1][j].first+val1,dp[i][j-1].first+val2);
                    dp[i][j]={tmp,t1};
                }
                pre2[a2[j]]++;
            }
            pre1[a1[i]]++;
        }
        cout<<dp[n][m].second<<'\n';
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/610503
推荐阅读
相关标签
  

闽ICP备14008679号