IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2022年寒假训练赛第3场 -> 正文阅读

[数据结构与算法]2022年寒假训练赛第3场

A:一二五八

题目描述

X星球有一个部落一直沿用着一套古老的货币。这套货币一共有四种面值,分别是1星、2星、5星和8星。X星人决定携带总金额为N星的货币来进行一次环球旅行,因为需要携带的物品实在太多太多,他希望携带的货币数量能够最少。
你能否编写一个程序帮助X星人计算出需要携带的最少货币数量?

输入

单组输入。每组一个正整数N,表示X星人携带的总金额。(N<=10^3)

输出

输出X星人最少需要携带的货币数量。

  • 贪心
  • 能用多少8星就用多少
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
int main(){
    int n;
    scanf("%d",&n);
    int ans=n/8;
    n%=8;
    if(n==1||n==2||n==5)ans++;
    else if(n)ans+=2;
    printf("%d\n",ans);
    return 0;
}

B:和为1

题目描述

给出n个正整数,这n个正整数中可能存在一些相同的数。现在从这n个数中选取m个正整数,分别记为X1、X2、…、Xm,使得这m个数满足如下公式:
1/X1 + 1/X2 + … + 1/Xm = 1
请问存在多少种不同的数字组合可以使得上述公式得以成立?

输入

单组输入。
第1行输入一个正整数n,表示输入的正整数个数。(n<=100)
第2行输入n个正整数,两两之间用空格隔开。

输出

输出满足要求的组合个数。如果一个组合都不存在,则输出“No solution!”。

  • 搜索
  • 找到一组和为1的数很容易,直接搜索,但是答案很多重复的组,所以要加判重
  • 搜索:分为分子,分母,每次选的数与当前选的分母求出最小公倍数组成新的分母,再求出分子,继续搜索
  • 判重:先对数组从小到大排序,每一组选的数用字符串s连接,在记录答案时,只记录第一次出现的答案字符串
  • 最后一发AC91%,改了好久的判重
#include<bits/stdc++.h>
using namespace std;
int a[105];
int ans,n;
map<string,bool>vis;
int gcd(int x,int y){//最大公约数
    return y==0 ? x:gcd(y,x%y);
}
int lcm(int x,int y){//最小公倍数
    return x*y/gcd(x,y);
}
void dfs(int fz,int fm,string s,int pos){

    if(fz==fm&&fz){
        if(!vis[s])//判重
            ans++;
        vis[s]=1;
        return ;
    }
    if(pos>n)return ;
    if(fz==0)dfs(1,a[pos],s+to_string(a[pos]),pos+1);
    else {
        int m=lcm(a[pos],fm);
        int z=(m/a[pos])+(m/fm)*fz;
        int g=gcd(m,z);
        dfs(z/g,m/g,s+to_string(a[pos]),pos+1);
    }
    dfs(fz,fm,s,pos+1);

}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    dfs(0,0,"",1);
    if(ans)printf("%d\n",ans);
    else printf("No solution!\n");
    return 0;
}

C:素数拆分

题目描述

如果将一个n(n>=2)位的素数拆分成两部分,其中高m位是一个素数,低(n-m)位也是一个素数,那么这个数称为可拆分素数。
例如113,它可以拆成两部分,高两位11是一个素数,低一位3也是一个素数,因此113是一个可拆分素数。
现在输入两个正整数M和N(M<N),请编写一个程序计算M到N之间有多少个可拆分素数(可以包含M和N)。

输入

单组输入。
输入两个正整数M和N(10<=M<N<=10^6)。

输出

输出M和N之间可拆分素数的个数(包含M和N)。

  • 枚举
  • 先筛法求出2~m之间的素数,然后枚举n-m之间的数,判断是否是可拆分素数
  • 判断素数是否可拆分也是枚举,枚举前后各多少个数
  • 代码可能比我说的容易看懂
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
int n,m;
bool isprime[1000005];
void prime(){//筛法求素数
 
    int i,j;
    isprime[0] = false;
    isprime[1] = false;
    isprime[2] = true;
 
    for(i=3; i<=m; i++) {
        isprime[i++] = true;
        isprime[i] = false;
    }
    int ma = sqrt(m);
    for(i=3; i<=ma; i++){
        if(isprime[i]) {
            for(j=i+i; j <= m; j+=i)
                isprime[j] = false;
        }
    }
}
bool check(int i){//判断一个素数是否可拆分
    int x=10;
    while(x<=i){
        if(isprime[i/x]&&isprime[i%x])
            return 1;
        x*=10;
    }
    return 0;
}
void cnt(){
    int ans=0;
    for(int i=n;i<=m;i++){
        if(isprime[i]&&check(i)){
            ans++;
        }
    }
    printf("%d\n",ans);
}
int main(){
 
    scanf("%d%d",&n,&m);
    prime();
    cnt();
    return 0;
}

D:空心圆柱

题目描述

小米同学用薄纸片卷了N个空心的小圆柱,他想把一些小的空心圆柱嵌到大的空心圆柱里面。
已知每一个空心圆柱的底面半径,在不考虑薄纸片本身厚度的情况下,请问这些空心圆柱最多可以嵌套多少层?

输入

单组输入。
第1行输入一个正整数N表示空心小圆柱的总数量。(N<=10^3)
第2行输入N个正数(有整数也有小数,最多不超过八位小数),表示N个空心小圆柱底面半径。

输出

输出最多可以嵌套的空心圆柱的数量。

  • 水题
  • 判断多少个不同的半径的圆柱就行
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
int n;
double a[1005];
int main(){
 
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf",&a[i]);
    }
    sort(a+1,a+1+n);
    int ans=0;
    for(int i=1;i<=n;i++){
        if(a[i]!=a[i-1])ans++;
    }
    printf("%d\n",ans);
    return 0;
}

E:营救行动

题目描述

X星卫士接到了一个紧急任务。大BOSS被困Y星的地狱迷宫,X星卫士必须携带“时空转移丸”尽快前往营救。
Y星的地狱迷宫是一个有M*N个小房间构成的矩形结构,迷宫中的小房间一共有M行,每一行有N列。
迷宫的入口为第1行第1列,标记为“S”,大BOSS被困的位置标记为“B”。
X星卫士通过每个普通小房间的时间均为1分钟。但是在这个迷宫中,有一些房间中设置了机关,一共包含三类不同的机关,分别是:死亡陷阱、延时陷阱和定向陷阱。死亡陷阱是不能进入的房间,一旦进入将万劫不复,营救失败;延时陷阱中布满死亡光线,需要3分钟时间才能够顺利通过;定向陷阱中设有一个定向诱导装置,进入该房间者将丧失转向功能(只在该房间中丧失),只能沿着直线行进,例如从左边进入只能从右边出来,从上面进入只能从下面出来,不过通过时间还是1分钟。
对于一个给定的地狱迷宫地图,请问最少需要多少时间(分钟)才能够营救到大BOSS(进入BOSS房间不消耗步数)?

输入

单组输入。
第1行输入两个正整数M和N,分别表示迷宫矩阵的行和列。(M<=103,N<=103)
第2行到第M+1行,每行N列,对应一个二维字符矩阵,用于表示地狱迷宫。
在字符矩阵中,“S”表示迷宫入口,“B”表示大BOSS被困的位置,“0”表示可以正常通过的房间(通过时间为1分钟),“#”表示死亡陷阱,“*”表示延时陷阱,“@”表示定向陷阱。

输出

X星卫士营救到大BOSS所需最少时间(单位:分钟);如果不能营救成功,则输出“Failure"。

  • 搜索
  • 在矩阵上的搜索,关于搜索强推我这篇博客 搜索专题:DFS
  • 这里是最短路模板,所以用bfs快一点,唯一要注意的就是@情况,是要延同一个方向一直走,直到走到一个不为@的地方
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m;
int d[][2]={0,1,1,0,0,-1,-1,0};
int dis[1005][1005];
char a[1005][1005];
struct node{
    int x,y;
    int ans;
    bool operator <(const node &q)const{
        return ans>q.ans;
    }
};
int ans;
bool check(int x,int y){
    if(x>=1&&x<=n&&y>=1&&y<=m&&a[x][y]!='#')
        return 1;
    return 0;
}
void bfs(){
    priority_queue<node>q;
    q.push({1,1,0});
    while(!q.empty()){
        node k=q.top();
        q.pop();
        if(a[k.x][k.y]=='B'){
            ans=k.ans-1;
            return ;
        }
        if(dis[k.x][k.y])continue;
        dis[k.x][k.y]=1;
        for(int i=0;i<4;i++){
            int x=k.x+d[i][0];
            int y=k.y+d[i][1];
            if(check(x,y)){
                if(a[x][y]=='0'||a[x][y]=='B')q.push({x,y,k.ans+1});
                else if(a[x][y]=='*')q.push({x,y,k.ans+3});
                else if(a[x][y]=='@'){
                    int res=k.ans;
                    while(check(x,y)&&a[x][y]=='@'){
                        dis[x][y]=1;
                        x+=d[i][0];
                        y+=d[i][1];
                        res++;
                    }
                    if(check(x,y)){
                        if(a[x][y]=='0'||a[x][y]=='B')
                            q.push({x,y,res+1});
                        else if(a[x][y]=='*')
                            q.push({x,y,res+3});
                    }
                }
            }
        }
    }
    return ;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",a[i]+1);
    }
    bfs();
    if(ans)printf("%d\n",ans);
    else puts("Failure");
    return 0;
}

F:a碟的微机

题目描述

a碟最近刚考完微机,他觉得这门课学的太痛苦了,于是想出了一些好(wu)玩(liao)的题目,有一段数据在地址线上串行传送(将数据分解成二进制位用一条信号线,一位一位顺序传送的方式)。a碟突发奇想(乱想),将二进制位的0当作“(”,1当作“)”,如果一串数据中的"01"完全匹配(例如01, 0011, 001011),则输出“Good”,若不是完全匹配(例如001,10,0111),则输出"Bad" 。
现在给你一段数据长度为n的串s(n<=1e5),请你判断这段数据是否满足上述定义?

输入

输入一串数据串s,其长度<=1e5

输出

如果该数据串中的"01"完全匹配,则输出"Good",否则输出"Bad"

  • 模拟
  • 就是一个括号匹配,堆栈模拟一下就好了,也比较水
#include<bits/stdc++.h>
#define ll long long
using namespace std;
bool cmp(string s){
    stack<char>st;
    for(int i=0;i<s.size();i++){
        if(s[i]=='1'){
            if(!st.empty())
                st.pop();
            else return 0;
        }else{
            st.push(s[i]);
        }
    }
    if(st.empty())return 1;
    else return 0;
}
int main(){
    string s;
    cin>>s;
    if(cmp(s))puts("Good");
    else puts("Bad");
    return 0;
}

G:a碟的备忘录

题目描述

a碟本学期学习了安卓开发,他的同学ph经常忘记事情,于是他想做一个简单的备忘录帮助ph。
他希望他的备忘录包含以下功能:
1、向备忘录插入字符串 s(英文字符)
2、删除备忘录最后k个字符(保证不为空串)
3、输出备忘录第k个字符(保证不为空串)
4、撤销最近的1或2操作,使备忘录回到1(或者2)操作之前的状态
可是a碟琢磨了半天还是做不来,聪明的你能解决a碟的问题,帮助ph吗?

输入

第一行输入一个整数t,代表总的操作数量
以下t行每行描述了一个操作,每行以一个整数n开始(1 <= n <= 4)。
n表示上述问题陈述中定义的操作类型。 如果操作需要参数,则后跟空格分隔的参数。
题目保证所有操作均合法
1 <= t <= 10^6
1 <= k <= |记事本内容长度|
每个测试数据中s的总长度 <= 10^6

输出

只有操作3需要输出结果,每行以换行符结束。

  • 模拟
  • 直接用字符串模拟(这个不难啊,为啥没啥人做,难道是我的开题顺序影响了大家做题
#include<bits/stdc++.h>
using namespace std;
#define ll long long
string s2[1000005];
 
int main(){
 
     int n;
     cin>>n;
     int d,k;
     string s1,str="";
     int pos=1;
     for(int i=1;i<=n;i++){
        cin>>d;
        if(d==1){
            cin>>s1;
            s2[pos++]=str;
            str+=s1;
        }
        else if(d==2){
            cin>>k;
            s2[pos++]=str;
            str=str.substr(0,str.size()-k);
        }
        else if(d==3){
            cin>>k;
            cout<<str[k-1]<<endl;
        }
        else {
            str=s2[--pos];
        }
     }
     return 0;
 }

H:X星人的密码

题目描述

聪明的X星人决定向在外太空的同伴发送一封非常非常重要的文件,该文件需要输入一个特殊的密码才能够打开。
这个特殊的密码是一串数字,这串数字密码需要通过解析一个包含很多正整数的文件才能够得到。
数字密码由三部分组成,这三部分对应三个正整数:第1部分是文件中所包含的最大正整数,第2部分是文件的正整数序列中所包含的最长单调递减子序列的长度,第3部分是文件中所包含的最小正整数。如果你得到了这三个部分,它们连接而成得到的数字字符串就是破解文件所需的密码。
X星人正在寻求你的帮助,你需要编写一个程序帮助他提取文件中蕴含的密码。

输入

单组输入。
第1行输入一个正整数N,表示文件中的正整数个数。(N<=1000)
第2行输入N个正整数,两两之间用空格隔开。最大正整数不超过10^6。

输出
输出文件中蕴含的数字密码。

  • 最长单调递减子序列的长度,将数组倒序就相当于最长上升子序列长度
  • 堆栈模拟,因为这个好记
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
int a[1005];
int n;
int lis(){
    reverse(a+1,a+1+n);
    vector<int>stk;
    stk.push_back(a[1]);
    for (int i = 2; i<=n; ++i) {
        if (a[i] > stk.back())
            stk.push_back(a[i]);
        else
            *lower_bound(stk.begin(), stk.end(), a[i]) = a[i];
    }
    return stk.size();
}
int main(){
 
    while(~scanf("%d",&n)){
        int ma=-INF,mi=INF;
        for(int i=1;i<=n;i++){
             scanf("%d",&a[i]);
             if(a[i]>ma)ma=a[i];
             if(a[i]<mi)mi=a[i];
        }
 
        printf("%d%d%d\n",ma,lis(),mi);
    }
    return 0;
}

I:重复DNA子片段

题目描述

给定一段由A、G、C和T这四种字符组成的DNA片段。
请编写一个程序计算该DNA片段中所包含的最长且不重叠的重复DNA子片段的长度。
例如:如果输入是“AAAAA”,则最长且不重叠的重复DNA子片段的长度为2,因为对应的不重叠最长重复子片段是“AA”。

输入

单组输入。
输入一段由A、G、C和T这四种字符组成的DNA片段。(1<=长度<=3000)

输出

输出最长且不重叠的重复DNA子片段的长度。

  • 字符串dp
  • 注意重复的字符串不能有重叠
#include<bits/stdc++.h>
using namespace std;
int dp[3005][3005];
int main(){

    string s;
    int ans=0;
    cin>>s;
    for(int i=1;i<=s.size();i++){
        for(int j=1;j<=s.size();j++){
            if(i!=j&&s[i-1]==s[j-1]){
                dp[i][j] = dp[i-1][j-1]+1;
                if(dp[i][j]>ans&&ans<abs(i-j))
                       ans=dp[i][j];
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 19:10:58  更:2022-01-30 19:11:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 17:27:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码