当前位置: 首页 > news >正文

备战蓝桥杯(非专业C++版)

洛谷:P1518\1781\1217\3406\3375



1-5:1518\1781\1217\3406\3375

1.P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two

难度:

问题描述:

  在一个10x10的方格牧场中:

  • 农夫(F)和牛(C)一开始位于不同位置。

  • 每秒钟,两者都尝试朝着他们面朝的方向移动。

    • 如果前面是围栏(*)或出界,就原地转向(右转90度),不移动。

  • 每秒两者会 同时 进行一次动作。

  • 问:他们多久能碰面?若永远碰不到,输出0。

P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two - 洛谷

分析与思路

这题是纯模拟题,模拟两者的运动状态,包括坐标位置(x,y)和面朝方向(d=0,1,2,3)。所有的运动状态(每次运动的可显示的结果)一共有,10*10*4*10*10*4种,我们要记录访问过的所有状态(f位置+f方向+c位置+c方向)。无法相遇说明进入了一种死循环的状态,所以重复即无法相遇。

  • 农夫 F 和奶牛 C 都从地图上的某个位置出发,初始都面朝“上”。

  • 每秒它们都:

    1. 看看正前方是否为墙('*');

    2. 如果是墙,就顺时针转向;

    3. 如果不是墙,就向前走一步;

  • 你要模拟每一秒的动作,直到它们两个“站在同一个格子”。

  • 如果永远无法相遇,输出 0

代码部分:
#include <iostream>
#include <cstring>
using namespace std;

struct Entity {
    int x, y, dir; // 位置 + 面朝方向
};

char m[12][12]; // 地图
bool visited[11][11][4][11][11][4]; // 状态记录

int dx[4] = {-1, 0, 1, 0}; // 上右下左
int dy[4] = {0, 1, 0, -1};

// 尝试移动实体
void move(Entity &e) {
    int nx = e.x + dx[e.dir];
    int ny = e.y + dy[e.dir];
    if (m[nx][ny] != '*') {
        e.x = nx;
        e.y = ny;
    } else {
        e.dir = (e.dir + 1) % 4; // 顺时针转向
    }
}

int main() {
    Entity farmer, cow;

    // 初始化地图边界为障碍
    for (int i = 0; i < 12; i++) {
        for (int j = 0; j < 12; j++) {
            m[i][j] = '*';
        }
    }

    // 读取地图(1~10)
    for (int i = 1; i <= 10; i++) {
        for (int j = 1; j <= 10; j++) {
            cin >> m[i][j];
            if (m[i][j] == 'F') {
                farmer = {i, j, 0}; // 初始朝上
            }
            if (m[i][j] == 'C') {
                cow = {i, j, 0}; // 初始朝上
            }
        }
    }

    int time = 0;
    while (true) {
        if (visited[farmer.x][farmer.y][farmer.dir][cow.x][cow.y][cow.dir]) {
            cout << 0 << endl;
            return 0; // 已经访问过这个状态,说明进入循环
        }

        visited[farmer.x][farmer.y][farmer.dir][cow.x][cow.y][cow.dir] = true;

        if (farmer.x == cow.x && farmer.y == cow.y) {
            cout << time << endl;
            return 0;
        }

        move(farmer);
        move(cow);
        time++;
    }

    return 0;
}

2.P1781宇宙总统

难度: 

问题描述:

有 n 位候选人,每人都有一个 竞选编号(可以非常长,有上千位数字)。

总统是编号字典序最大的那一位。

编号长度最长为 100(可能超过 long long),所以不能直接转数字比较,要用字符串比较。

P1781 宇宙总统 - 洛谷

分析与思路:

存储长数字用string,比较大小,可以利用位数和大小相结合的方法。

代码部分:
//P1781
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

struct no1{
	string x;//票数
	int num;//几号
	int lenx;//票数的位数 
};
bool cmp(no1 a,no1 b){//排序规则 
	return (a.lenx>b.lenx||(a.lenx==b.lenx && a.x>b.x));
}
int main(){
	int n;
	cin>>n;
	no1 s[n+1];
	for(int i=1;i<=n;i++){
		cin>>s[i].x;
		s[i].num=i;
		s[i].lenx=s[i].x.size();
	}
	
	sort(s+1,s+1+n,cmp);
	cout<<s[1].num<<endl;
	cout<<s[1].x<<endl;
	return 0;
} 

3.P1217 [USACO1.5] 回文质数 Prime Palindromes

P1217 [USACO1.5] 回文质数 Prime Palindromes - 洛谷

难度: 

判断质数:

bool isprime(int a){
    if (a<2) return 0;
    for(int i=2;i<=int(sqrt(a));i++){
        if(a%i==0) return 0;
    }
    return 1;
}

判断回文数:
bool huiwen(int a){
    string s=to_string(a);
    string t=s;
    reverse(t.begin(),t.end());
    return s==t;
}

代码部分:
#include <iostream>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;

bool isprime(int a){
	if (a<2) return 0;
	for(int i=2;i<=int(sqrt(a));i++){
		if(a%i==0) return 0;
	}
	return 1;
}
bool huiwen(int a){
	string s=to_string(a);
	string t=s;
	reverse(t.begin(),t.end());
	return s==t;
}

int main(){
	int a,b;
	cin>>a>>b;
	for(int i=a;i<=b;i++){
		if(isprime(i)&&huiwen(i)) cout<<i<<endl;
	}
	return 0;
}

4.P3406 海底高铁(差分数组+前缀和)

难度:  

问题描述:

铁路连接了 N 个城市,每个城市有一个车站。由于各城市间未能协调统一,乘客在经过两个相邻城市之间时,需单独购买该段车票。第 i 段铁路连接城市 i 和城市 i+1,购买该段铁路的票有两种方式:​

  • 单程票:每次乘坐需支付 A[i] 元。
  • IC卡:需支付 C[i] 元的工本费购买IC卡,之后每次乘坐该段铁路仅需支付 B[i] 元。

给定乘客的旅行计划,需计算出使总费用最小的购票策略。一般来说,同一个地方去的次数够多,买IC卡还是比较优惠的。

变量解释:一个N个城市、要去M个城市、按Pi的顺序访问M个城市、Ai是票的原价、Ci是票的开卡费、Bi是票的优惠费。

分析与思路:

为了最小化总费用,局部最优就是全局最优。我们需要统计一下每段铁路的同行次数,再决定哪种方式同行比较好。

1.计算每一段路的经过次数

由于每次访问的城市可能不相邻,即Pi和Pi+1可能隔着好几个城市,而且路径之间还可能存在重叠,那么每次经过这段路时可以记下来这段路的次数。我们想知道 每一段铁路(城市 i 到 i+1)被走了几次,但如果直接对每一段路径都遍历和累加,复杂度会很高(尤其是当路径很长时)。
差分数组的关键思想是:只记录“变化”(一般是加减某个特定的值),然后通过前缀和恢复“完整信息”。前缀和算法(c++版)_c++前缀和-CSDN博客

  • 对于每次从城市 P[i]P[i+1] 的旅行:​

    • P[i] < P[i+1],则在差分数组 vis 中:​

      • vis[P[i]] += 1vis[P[i+1]] -= 1(加和后表示从pi--pi+1的城市序列中,每个城市+1)

    • P[i] > P[i+1],则:​

      • vis[P[i+1]] += 1vis[P[i]] -= 1

然后,对差分数组求前缀和,即可得到每段铁路的实际通行次数。

for (int i = 1; i < N; ++i) {
    vis[i] += vis[i-1];
}

2. 计算最小费用

对于每段铁路,计算以下两种方式的费用,并取最小值累加:​

  • 购买单程票的总费用A[i] * 通行次数

  • 购买IC卡的总费用C[i] + B[i] * 通行次数

代码部分:
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int N, M;
    cin >> N >> M;

    vector<int> P(M + 1);
    for (int i = 1; i <= M; ++i) {
        cin >> P[i];
    }

    vector<int> A(N), B(N), C(N);
    for (int i = 1; i < N; ++i) {
        cin >> A[i] >> B[i] >> C[i];
    }

    vector<int> vis(N + 1, 0);//差分的数组,方便加某一段的次数

    for (int i = 1; i < M; ++i) {
        int l = min(P[i], P[i + 1]);
        int r = max(P[i], P[i + 1]);
        vis[l]++;
        vis[r]--;//注意截止位置,假设2-5之间的城市只有三段距离
    }

    for (int i = 1; i <= N; ++i) {
        vis[i] += vis[i - 1];//获得完整路径
    }

    long long total_cost = 0;
    for (int i = 1; i < N; ++i) {
    //static_cast<long long>类型转换方式,它将某个值安全地转换为 long long 类型
        long long single_ticket_cost = static_cast<long long>(A[i]) * vis[i];
        long long ic_card_cost = static_cast<long long>(B[i]) * vis[i] + C[i];
        total_cost += min(single_ticket_cost, ic_card_cost);
    }

    cout << total_cost << endl;

    return 0;
}

5.P3375 【模板】KMP

问题描述:

给定两个字符串 S(主串)和 T(模式串),输出:

  1. 所有模式串 T 在主串 S 中出现的位置(从 1 开始编号)

  2. 模式串 T 的 next 数组

思路与推导:

先验知识:在模式串匹配过程中,为优化匹配方式而进行的操作。原理分析,进行串的匹配时,模式串比到中间发现不匹配了,下一步应该如何操作呢,对于模式串,前面若有公共前后缀的话,直接让开头前缀的位置放到后缀的位置继续往下比。这样可以直接跳过原来一步步的操作。如下图,

没有公共前后缀的话,只能从头比喽。

下面是手推的写法,之前整理过的。

那么如何求next[]以及nextval[]?就涉及到代码部分了

代码部分:
#include <stdio.h>
#include <string.h>

// 计算模式串 t 的 next 数组
void GetNext(char t[], int next[]) {
    int j = 0;      // 指向当前正在计算 next[j] 的位置
    int k = -1;     // 指向 t[0...k-1] 是当前前缀与后缀相等的最大长度
    next[0] = -1;   // next[0] 总是 -1,表示第一个字符无前缀

    // 遍历整个模式串
    while (t[j] != '\0') {
        if (k == -1 || t[j] == t[k]) {
            // 情况1:k==-1 说明回退到底了,或 t[j]==t[k] 表示继续匹配成功
            j++;
            k++;
            next[j] = k; // 记录前缀长度 k 到 next[j]
        } else {
            // 情况2:失配,回退 k 到 next[k]
            k = next[k];
        }
    }
}
// 计算模式串 t 的 nextval 数组
void GetNextval(char t[], int nextval[]) {
    int j = 0;        // 正在计算 nextval[j]
    int k = -1;       // 同样是最长公共前后缀长度指针
    nextval[0] = -1;  // 初始定义

    while (t[j] != '\0') {
        if (k == -1 || t[j] == t[k]) {
            // 情况1:继续匹配或 k==-1,更新 j 和 k
            j++;
            k++;

            if (t[j] != t[k]) {
                // 如果下一个字符不等,则 nextval[j] = k,正常赋值
                nextval[j] = k;
            } else {
                // 如果下一个字符也相等,跳过重复匹配段(优化)
                nextval[j] = nextval[k];
            }
        } else {
            // 情况2:失配时回溯 k 到 nextval[k]
            k = nextval[k];
        }
    }
}

  可视化每一步操作

#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;

void GetNext(char t[], int next[]) {
    int j = 0;
    int k = -1;
    next[0] = -1;

    cout << "=== GetNext 过程 ===" << endl;
    cout << "步骤\tj\tk\tt[j]\tt[k]\t操作\t\t\tnext[j]" << endl;

    while (t[j] != '\0') {
        if (k == -1 || t[j] == t[k]) {
            j++;
            k++;
            next[j] = k;

            cout << setw(2) << j << '\t'
                 << setw(2) << j << '\t'
                 << setw(2) << k << '\t'
                 << (t[j] ? t[j] : '-') << '\t'
                 << (t[k] ? t[k] : '-') << '\t'
                 << "匹配/初始\t\tnext[" << j << "] = " << k << endl;
        } else {
            cout << setw(2) << j << '\t'
                 << setw(2) << j << '\t'
                 << setw(2) << k << '\t'
                 << t[j] << '\t'
                 << t[k] << '\t'
                 << "失配回退\tk = next[" << k << "] = " << next[k] << endl;
            k = next[k];
        }
    }
    cout << "====================" << endl << endl;
}

void GetNextval(char t[], int nextval[]) {
    int j = 0;
    int k = -1;
    nextval[0] = -1;

    cout << "=== GetNextval 过程 ===" << endl;
    cout << "步骤\tj\tk\tt[j]\tt[k]\t操作\t\t\tnextval[j]" << endl;

    while (t[j] != '\0') {
        if (k == -1 || t[j] == t[k]) {
            j++;
            k++;
            if (t[j] != t[k]) {
                nextval[j] = k;
                cout << setw(2) << j << '\t'
                     << setw(2) << j << '\t'
                     << setw(2) << k << '\t'
                     << t[j] << '\t'
                     << t[k] << '\t'
                     << "正常赋值\t\tnextval[" << j << "] = " << k << endl;
            } else {
                nextval[j] = nextval[k];
                cout << setw(2) << j << '\t'
                     << setw(2) << j << '\t'
                     << setw(2) << k << '\t'
                     << t[j] << '\t'
                     << t[k] << '\t'
                     << "跳过重复\t\tnextval[" << j << "] = nextval[" << k << "] = " << nextval[j] << endl;
            }
        } else {
            cout << setw(2) << j << '\t'
                 << setw(2) << j << '\t'
                 << setw(2) << k << '\t'
                 << t[j] << '\t'
                 << t[k] << '\t'
                 << "失配回退\tk = nextval[" << k << "] = " << nextval[k] << endl;
            k = nextval[k];
        }
    }
    cout << "=======================" << endl << endl;
}

int main() {
    char t[] = "abcaabbcabccbaadab";
    int next[100], nextval[100];

    GetNext(t, next);
    GetNextval(t, nextval);

    return 0;
}

相关文章:

  • 蓝桥杯 拼数(字符串大小比较)
  • 9.访问数据库2
  • 一个插件,免费使用所有顶级大模型(Deepseek,Gpt,Grok,Gemini)
  • 设计模式:抽象工厂 - 掌控多产品族的创建之道
  • # 实时人脸性别与年龄识别:基于OpenCV与深度学习模型的实现
  • Elasticsearch 超详细教程:从入门到精通
  • 《Uniapp-Vue 3-TS 实战开发:从入门到精通》专栏介绍
  • 15. git remote
  • 加密相关的知识点
  • 人-AI-环境系统智能赋能工程项目管理
  • 算法系列——无监督学习——13.LDA
  • 在 Windows 上安装 WSL Ubuntu 的完整避坑指南:从报错到成功运行
  • 深入理解 React useLayoutEffect:精准掌控 DOM 更新时机
  • vscode中REST Client插件
  • 3-1 Git分布式版本控制特性探讨
  • Ansible(8)——循环与条件任务
  • 10-MySQL-性能优化思路
  • web前端 html常用标签
  • Java 设计模式:策略模式详解
  • 使用 Fabric.js 构建一个在线白板组件(支持绘图 / 拖拽 / 导出)
  • 网站建设要具备那些/西安百度推广联系方式
  • 宁夏信用建设官方网站/长沙官网优化公司
  • 片头制作网站/百度收录入口
  • 网站主要栏目/东莞seo网站排名优化公司
  • 网站里面网友点评怎么做/成人技术培训班有哪些种类
  • 所以免费爱做网站/seo 是什么