第十四次CCF计算机软件能力认证

第一题:买菜

在一条街上有 n 个卖菜的商店,按 1 至 n 的顺序排成一排,这些商店都卖一种蔬菜。

第一天,每个商店都自己定了一个价格。

店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。

具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。

注意,编号为 1 的商店只有一个相邻的商店 2,编号为 n 的商店只有一个相邻的商店 n−1,其他编号为 i 的商店有两个相邻的商店 i−1 和 i+1。

给定第一天各个商店的菜价,请计算第二天每个商店的菜价。

输入格式

输入的第一行包含一个整数 n,表示商店的数量。

第二行包含 n 个整数,依次表示每个商店第一天的菜价。

输出格式

输出一行,包含 n 个正整数,依次表示每个商店第二天的菜价。

数据范围

对于所有评测用例,2≤n≤1000,第一天每个商店的菜价为不超过 1e4 的正整数。

输入样例:

8
4 1 3 1 6 5 17 9

输出样例:

2 2 1 3 4 9 10 13

解题思路:

根据题目进行模拟即可

cpp 复制代码
#include<iostream>

using namespace std;

const int N = 1010;
int a[N];
int n;

int main()
{
    cin >> n;
    for(int i = 0;i < n;i ++) cin >> a[i];
    
    cout << (a[0] + a[1]) / 2;
    
    for(int i = 1;i < n - 1;i ++)
        cout << " " << (a[i] + a[i - 1] + a[i + 1]) / 3;
    
    cout << " " << (a[n - 2] + a[n - 1]) / 2;
    return 0;
}

第二题:买菜

小 H 和小 W 来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买 n 种菜,所以也都要装 n 次车。

具体的,对于小 H 来说有 n 个不相交的时间段 [a1,b1],[a2,b2]...[an,bn]在装车,对于小 W 来说有 n 个不相交的时间段 [c1,d1],[c2,d2]...[cn,dn] 在装车。

其中,一个时间段 [s,t] 表示的是从时刻 s 到时刻 t 这段时间,时长为 t−s。

由于他们是好朋友,他们都在广场上装车的时候会聊天,他们想知道他们可以聊多长时间。

输入格式

输入的第一行包含一个正整数 n,表示时间段的数量。

接下来 n 行每行两个数 ai,bi,描述小 H 的各个装车的时间段。

接下来 n 行每行两个数 ci,di,描述小 W 的各个装车的时间段。

输出格式

输出一行,一个正整数,表示两人可以聊多长时间。

数据范围

对于所有的评测用例,1≤n≤2000,ai<bi<ai+1,ci<di<ci+1,对于所有的 i(1≤i≤n) 有,1≤ai,bi,ci,di≤1e6。

输入样例:

4
1 3
5 6
9 13
14 15
2 4
5 7
10 11
13 14

输出样例:

3

解题思路:

如果两个时间有交集一定是前一个的时间段的最后时刻,大于第二个时间段的开始时刻

根据这个思路最终答案一定是最小的终点时间 - 最大的开始时间

cpp 复制代码
#include<iostream>
#include<cstring>

using namespace std;

#define x first
#define y second

typedef pair<int, int> PII;
const int N = 2010;
int n;
PII p[N], q[N];

int get(PII a, PII b)
{
    if (a.y < b.x || b.y < a.x) return 0;
    return min(a.y, b.y) - max(a.x, b.x);
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> p[i].x >> p[i].y;
    for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
    int res = 0;
    
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            res += get(p[i], q[j]);
    cout << res << endl;

    return 0;
}

第三题:元素选择器

题目略

解题思路:

模拟,数据量很小可以直接暴力搜索进行枚举

坑点:

(1)标签:大小写不敏感

(2)属性:大小写敏感

(3)后代选择器:从前往后找父节点,找到倒数第二个父节点的行号,从这个往后找满足最后一个元素的行号。

方法:

使用sstream进行读取

stringstream进行读取,不需要枚举位置

cpp 复制代码
// 数据量很小
#include<iostream>
#include<sstream>
#include<vector>

using namespace std;

const int N = 110;
int n , m;
string s;

struct node
{
    int type;
    // id表示标签 main表示属性
    string id , main;
}nodes[N];

string change(string t)
{
    string res;
    for(auto i : t)
    {
        if(i >= 'A' && i <= 'Z') res += (i ^ 32);
        else res += i;
    }
    return res;
}

void work(vector<string>&v)
{
    vector<int>res;
    
    if(v.size() == 1) 
    {
        // 属性 大小写敏感
        if(v[0][0] == '#')
        {
            for(int i = 0;i < n;i ++)
                if(nodes[i].main == v[0]) res.push_back(i + 1);
        }
        // 标签 大小写不敏感
        else
        {
            for(int i = 0;i < n;i ++)
                if(change(nodes[i].id) == change(v[0])) res.push_back(i + 1);
        }
    }
    else
    {
        int w = v.size();
        int j = 0 , temp = 0 , last = -1;
        for(int i = 0;i < n;i ++)
        { 
            if(j == w - 1)
            {
                temp = i;
                break;
            }
            // 属性 大小写敏感
            if(v[j][0] == '#') 
            {
                if(v[j] == nodes[i].main && (last == -1 || nodes[i].type > last)) j ++ , last = nodes[i].type;
            }
            else 
            {
                if(change(nodes[i].id) == change(v[j]) && (last == -1 || nodes[i].type > last)) j ++ , last = nodes[i].type;
            }
        }
        
        if(j == w - 1)
        {
            for(int i = temp;i < n;i ++)
            {
                if(v[j][0] == '#')
                {
                    if(v[j] == nodes[i].main && nodes[i].type > last) res.push_back(i + 1);
                }
                else
                {
                    if(change(nodes[i].id) == change(v[j]) && nodes[i].type > last) res.push_back(i + 1);
                }
            }
        }
    }
    cout << res.size() << " ";
    for(int i = 0;i < res.size();i ++)
        cout << res[i] << " ";
    cout << endl;
}

int main()
{
    cin >> n >> m;
    getchar();
    for(int i = 0;i < n;i ++)
    {
        getline(cin , s);
        stringstream ss(s);
        vector<string>v;
        while(ss >> s) v.push_back(s);
        int j = 0;
        while(j < v[0].size() && v[0][j] == '.') j ++;
        
        if(v.size() == 1) nodes[i] = {j / 2 , v[0].substr(j) , "****"};
        else nodes[i] = {j / 2 , v[0].substr(j) , v[1]};
    }
    
    while(m --)
    {
        getline(cin , s);
        stringstream ss(s);
        vector<string>v;
        while(ss >> s) v.push_back(s);
        
        work(v);
    }
    return 0;
} 

第四题:再买菜

在一条街上有 n 个卖菜的商店,按 1 至 n 的顺序排成一排,这些商店都卖一种蔬菜。

第一天,每个商店都自己定了一个正整数的价格。

店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。

具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。

注意,编号为 1 的商店只有一个相邻的商店 2,编号为 n 的商店只有一个相邻的商店 n−1,其他编号为 i 的商店有两个相邻的商店 i−1 和 i+1。

给定第二天各个商店的菜价,可能存在不同的符合要求的第一天的菜价,请找到符合要求的第一天菜价中字典序最小的一种。

字典序大小的定义:对于两个不同的价格序列 (a1,a2,...,an) 和 (b1,b2,b3,...,bn),若存在 i(i>=1),使得 ai<bi,且对于所有 j<i,aj=bj,则认为第一个序列的字典序小于第二个序列。

输入格式

输入的第一行包含一个整数 n,表示商店的数量。

第二行包含 n 个正整数,依次表示每个商店第二天的菜价。

输出格式

输出一行,包含 n 个正整数,依次表示每个商店第一天的菜价。

数据范围

对于 30% 的评测用例,2≤n≤5,第二天每个商店的菜价为不超过 10 的正整数;

对于 60% 的评测用例,2≤n≤20,第二天每个商店的菜价为不超过 100 的正整数;

对于所有评测用例,2≤n≤300,第二天每个商店的菜价为不超过 100 的正整数。

请注意,以上都是给的第二天菜价的范围,第一天菜价可能会超过此范围。

数据保证一定有解。

输入样例:

8
2 2 1 3 4 9 10 13

输出样例:

2 2 2 1 6 5 16 10

解题思路:

对于每一个除去开头和结尾的两个元素

对于第一个元素

对于最后一个元素

又因为是向下取整,其中a的元素是连续的可以使用前缀和进行

因此使用差分约束+spfa解决

差分约束:
a----->b ab间有一条边长度为c
s[b] >= s[a] + c
c有可能是负数因此需要使用spfa

得出下面的结论

求最小值 使用最长路 SPFA
求最大值 使用最短路

cpp 复制代码
// 求最小值 使用最长路 SPFA
// 求最大值 使用最短路
#include<iostream>
#include<queue>
#include<cstring>

using namespace std;

const int N = 1e4 + 10;
int h[N] , ne[N] , w[N] , e[N] , idx;
int n , m;
int dist[N];
bool st[N];

void add(int a , int b , int c)
{
    e[idx] = b , w[idx] = c , ne[idx] = h[a] , h[a] = idx ++;
}

void spfa()
{
    // 最长路
    queue<int>q;
    // 最短路使用 memset(dist , 0x3f , sizeof dist);
    memset(dist , -0x3f , sizeof dist);
    dist[0] = 0;
    q.push(0);
    
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        st[t] = false;
        
        for(int i = h[t];~i;i = ne[i])
        {
            int j = e[i];
            if(dist[j] < dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }
}
int b[N];

int main()
{
    cin >> n;
    memset(h , -1 , sizeof h);
    
    for(int i = 1;i <= n;i ++)  cin >> b[i];
    
    /*
        差分约束:
        a----->b ab间有一条边长度为c
        s[b] >= s[a] + c
        c有可能是负数因此需要使用spfa
    
        其中s为前缀和
        对于不包括两边的元素
        满足 
        b[i] = (a[i - 1] + a[i] + a[i + 1]) / 3
        >>>> 3b[i] <= (s[i + 1] - s[i - 2]) <= 3b[i] + 2
        >>>> 1、s[i + 1] - s[i - 2] >= 3b[i]
        >>>> 2、3b[i] + 2 >= s[i + 1] - s[i - 2]
        
        >>>> 1、s[i + 1] >= s[i - 2] + 3b[i]
        >>>> 2、s[i - 2] >= s[i + 1] - 3b[i] - 2
        
        >>>> 1、add(i - 2 , i + 1 , 3b[i]);
        >>>> 2、add(i + 1 , i - 2 , -3b[i] - 2);
    */
    for(int i = 2;i < n;i ++)
    {
        add(i - 2 , i + 1 , 3 * b[i]);
        add(i + 1 , i - 2 , -3 * b[i] - 2);
    }
    
    /*
        b[1] = (a[0] + a[1]) / 2 
        
        >>>> 2b[1] <= s[2] - s[0] <= 2b[1] + 1
        >>>> 1、s[2] >= s[0] + 2b[1]
        >>>> 2、s[0] >= s[2] - 2b[1] - 1
        
        b[n] = (a[n] + a[n - 1]) / 2
        >>>> 1、s[n - 2] >= s[n] - 2b[n] - 1
        >>>> 2、s[n] >= s[n - 2] + 2b[n]
    */
    add(0 , 2 , 2 * b[1]) , add(2 , 0 , -2 * b[1] - 1);
    add(n - 2 , n , 2 * b[n]) , add(n , n - 2 , -2 * b[n] - 1);
    
    // s[i] >= s[i - 1] + 1   
    for(int i = 1;i <= n;i ++) add(i - 1 , i , 1);
    
    spfa();
    
    /*
        由于这里求出的是a数组的前缀和,题目要求输出a数组
        则最终答案为: dist[i] - dist[i - 1]
    */
    for(int i = 1;i <= n;i ++)
        cout << dist[i] - dist[i - 1] << " ";
    
    return 0;
}

第五题:线性递推式

感觉应该是DP+数学

cpp 复制代码
#include <iostream>
#define ll long long
using namespace std;
const int mod=998244353;
const int M=1e5+10;
ll k[M],b[M];
ll l,r;
int m;
int main()
{
    cin>>m>>l>>r;
    for(int i=1;i<=m;i++) cin>>k[i];
    b[0]=1;
    for(int i=1;i<=r;i++)
    {
        ll ans=0;
        for(int j=1;j<=min(i,m);j++)
        {
            ans=(ans+(k[j]*b[i-j]%mod))%mod;
        }
        b[i]=ans;
    }
    for(int i=l;i<=r;i++)cout<<b[i]<<endl;
    return 0;
}
相关推荐
好奇龙猫32 分钟前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
霁月风1 小时前
设计模式——适配器模式
c++·适配器模式
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
ChoSeitaku1 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程1 小时前
双向链表专题
数据结构
香菜大丸1 小时前
链表的归并排序
数据结构·算法·链表
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
oliveira-time2 小时前
golang学习2
算法
咖啡里的茶i2 小时前
Vehicle友元Date多态Sedan和Truck
c++
海绵波波1072 小时前
Webserver(4.9)本地套接字的通信
c++