CCF-CSP 201703 赛题训练

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF-CSP 201703 赛题训练相关的知识,希望对你有一定的参考价值。

这里写目录标题

【CCF CSP - 20170301】分蛋糕

题意概述

小明今天生日,他有 n 块蛋糕要分给朋友们吃,这 n 块蛋糕(编号为 1 到 n)的重量分别为 a 1 , a 2 , ⋯   , a n a_1,a_2,\\cdots,a_n a1,a2,,an。小明想分给每个朋友至少重量为 k 的蛋糕。小明的朋友们已经排好队准备领蛋糕,对于每个朋友,小明总是先将自己手中编号最小的蛋糕分给他,当这个朋友所分得蛋糕的重量不到 k 时,再继续将剩下的蛋糕中编号最小的给他,直到小明的蛋糕分完或者这个朋友分到的蛋糕的总重量大于等于 k。

请问当小明的蛋糕分完时,总共有多少个朋友分到了蛋糕。

输入输出格式

输入的第一行包含了两个整数 n、k,意义如上所述。第二行包含 n 个正整数,依次表示 a 1 , a 2 , ⋯   , a n a_1,a_2,\\cdots,a_n a1,a2,,an

输出一个整数,表示有多少个朋友分到了蛋糕。

C++ 代码

#include <bits/stdc++.h>
using namespace std;
using gg = long long;
int main() 
    ios::sync_with_stdio(false);
    cin.tie(0);
    gg ni, ki, ai;
    gg s = 0, ans = 0;
    cin >> ni >> ki;
    for (gg i = 0; i < ni; ++i) 
        cin >> ai;
        s += ai;
        if (i == ni - 1 or s >= ki) 
            ++ans;
            s = 0;
        
    
    cout << ans;
    return 0;

把输入看作流,一边读入数据,一边计算处理,是一种好的做法,可以节省存储。

#include<bits/stdc++.h>
using namespace std;

int main() 
    int n, k, cur = 0, sum = 0;
    cin >> n >> k;
    while (n--) 
        int x;
        cin >> x;
        cur += x;
        if (cur >= k) 
            cur = 0;
            sum++;
        
    
    if (cur > 0)
        sum++;
    cout << sum;

【CCF CSP - 20170302】学生排队

问题描述

体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。
  例如,下面给出了一组移动的例子,例子中学生的人数为8人。   
  0)初始队列中学生的学号依次为1, 2, 3, 4, 5, 6, 7,8;
  1)第一次调整,命令为“3号同学向后移动2”,表示3号同学出队,向后移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1,2, 4, 5, 3, 6, 7, 8;
  2)第二次调整,命令为“8号同学向前移动3”,表示8号同学出队,向前移动3名同学的距离,再插入到队列中,新队列中学生的学号依次为1,2, 4, 5, 8, 3, 6, 7;
  3)第三次调整,命令为“3号同学向前移动2”,表示3号同学出队,向前移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1,2, 4, 3, 5, 8, 6, 7。   
小明记录了所有调整的过程,请问,最终从前向后所有学生的学号依次是多少?
  请特别注意,上述移动过程中所涉及的号码指的是学号,而不是在队伍中的位置。在向后移动时,移动的距离不超过对应同学后面的人数,如果向后移动的距离正好等于对应同学后面的人数则该同学会移动到队列的最后面。在向前移动时,移动的距离不超过对应同学前面的人数,如果向前移动的距离正好等于对应同学前面的人数则该同学会移动到队列的最前面。

输入格式

输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。   
第二行包含一个整数m,表示调整的次数。
接下来m行,每行两个整数p, q,如果q为正,表示学号为p的同学向后移动q,如果q为负,表示学号为p的同学向前移动-q。

输出格式

输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,表示最终从前向后所有学生的学号。

样例输入

8
3
3 2
8 -3
3 -2

样例输出

1 2 4 3 5 8 6 7

评测用例规模与约定

对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。

方法一:

数组sno2pos[]用于存储各个学生(学号)所在的位置;数组pos2sno[]是索引,pos2sno[i]=s表示学生s位于位置i。这个程序应该是最快速的版本。Link

#include<bits/stdc++.h>
using namespace std;

const int N = 1000;

int sno2pos[N+1];  // 学号所在位置
int pos2sno[N+1];  // 位置上的学号

int main() 
    int n, m, p, q;
    
    // 读入数据
    cin >> n >> m;
    // 初始化
    for(int i = 1; i <= n; i++) 
        sno2pos[i] = i;
        pos2sno[i] = i;
    
    // 模拟移动过程
    for (int i = 1; i <= m; i++) 
        int pos1, pos2, sno2;
        cin >> p >> q;
        if (q != 0) 
            int move = (q > 0) ? 1:-1;  // 控制方向
            int end = (q > 0) ? q : -q;  // 控制移动次数
            
            pos1 = sno2pos[p];  // 当前学号所在位置
            for (int i = 1; i <= end; i++)   // 移动次数
                sno2 = pos2sno[pos1+move];  // 获取旁边的sno
                pos2 = sno2pos[sno2];  // 获取学号所在位置
                // 将旁边的sno前/后移
                pos2sno[pos1] = sno2;
                sno2pos[sno2] = pos1;
                pos1 = pos2;  // 实现迭代
            
            // 实现插入操作
            pos2sno[pos2] = p;
            sno2pos[p] += q;
        
    
    // 输出结果
    cout << pos2sno[1];
    for(int i = 2; i <= n; i++)
        cout << " " << pos2sno[i];  // 插入空格
         
    cout << endl;
 
    return 0;


方法二:

数组pos2sno[]用于存储各个所在的位置上的学生(学号),pos2sno[i]=s表示学生s位于位置i。这个方法是直接进行模拟。其缺点是每次需要找到指定学生(学号)的位置,顺序查找需要花费时间;优点是逻辑相对简单并且易于理解。

#include<bits/stdc++.h>
using namespace std;

const int N = 1000;
int stu[N];

//
int find(int sno) 
    int i;
    for (i = 1; stu[i] != sno; i++);
    return i;

int main() 
    int n, m, p, q;
    
    // 读入数据
    cin >> n >> m;
    // 初始化
    for(int i = 1; i <= n; i++) 
        stu[i] = i;
    
    // 模拟移动过程
    for (int i = 1; i <= m; i++) 
        cin >> p >> q;

        // 查找学号为p的位置
        int pos = find(p);

        if (q > 0) 
            for (int j = pos; j < pos+q; j++) 
                stu[j] = stu[j+1];  // 向前移动
            
            stu[pos+q] = p;  // 插入进去
         else 
             for (int j = pos; j > pos+q; j--) 
                stu[j] = stu[j-1];  // 向后移动
            
            stu[pos+q] = p;  // 插入进去
        
    
    // 输出结果
    cout << stu[1];
    for(int i = 2; i <= n; i++)
        cout << " " << stu[i];  // 插入空格
         
    cout << endl;
 
    return 0;


方法三:

使用链表来实现,是一种最容易想到的方法。这个程序的关键是如何使用STL的list(链表)实现模拟。

程序中的28-33行,有关迭代器指针移动的逻辑是不是可以改进?

/* CCF201703-2 学生排队 */
 
#include <iostream>
#include <algorithm>
#include <list>
 
using namespace std;
 
int main()

    int n, m, p, q;
    list<int> l;
 
    // 读入数据
    cin >> n >> m;
 
    // 初始化
    for(int i=1; i<=n; i++)
        l.push_back(i);
 
 
    // 模拟移动过程
    for(int i=1; i<=m; i++) 
        cin >> p >> q;
 
        list<int>::iterator iter = find(l.begin(), l.end(), p);
        list<int>::iterator iter2 = iter;
        if(q > 0)
            for(int i=0; i<=q; i++)
                iter2++;
        else
            for(int i=1; i<=-q; i++)
                iter2--;
        l.insert(iter2, p);
        l.erase(iter);
    
 
    // 输出结果
    list<int>::iterator iter = l.begin();
    cout << *iter;
    for(iter++; iter != l.end(); iter++)
        cout << " " << *iter;
    cout << endl;
 
    return 0;

方法四:

使用STL的向量vector来实现。实际上是一种代码最为简洁的做法。

需要注意的是下标运算逻辑。

/* CCF201703-2 学生排队 */
 
#include <iostream>
#include <vector>
 
using namespace std;
 
vector<int> v;
 
int find(int x)

    int ret = - 1;
    for(int i = 0; i < (int)v.size(); i++)
        if(v[i] == x)
            return i;
    return ret;

 
int main()

    int n, m, p, q;
 
    // 读入数据
    cin >> n >> m;
 
    // 初始化
    for(int i=1; i<=n; i++)
        v.push_back(i);
 
 
    // 模拟移动过程
    for(int i=1; i<=m; i++) 
        cin >> p >> q;
 
        int pos = find(p);
        v.insert(v.begin() + pos + (q > 0 ? q + 1 : q), p);
        v.erase(v.begin() + pos + (q < 0 ? 1 : 0));
    
 
    // 输出结果
    cout << v[0];
    for(int i = 1; i < (int)v.size(); i++)
        cout << " " << v[i];
    cout << endl;
 
    return 0;

代码来源Link

#include<bits/stdc++.h>
using namespace std;

vector<int> stu;

int main() 
    int n, m, p, q;
    
    // 读入数据
    cin >> n >> m;
    // 初始化
    for(int i = 1; i <= n; i++) 
        stu.push_back(i);
    
    int no, pos;
    vector<int>:: iterator it;  // 声明迭代器
    
    while (m--) 
        cin >> no >> pos;
        for (it = stu.begin(); it != stu.end(); it++) 
            if (*it == no)   // 判断值是否相等
                it = stu.erase(it);  // 根据地址删除
                stu.insert(it+pos, no);  // 插入到指定位置
                break;
            
        
    
    for (it = stu.begin(); it != stu.end(); it++) 
        cout << *it << " ";
    
    return 0;

代码来源:https://blog.csdn.net/wingrez/article/details/82560250

加油!

感谢!

努力!

以上是关于CCF-CSP 201703 赛题训练的主要内容,如果未能解决你的问题,请参考以下文章

CCF-CSP 201604 赛题训练

CCF-CSP 201612 赛题训练

CCF-CSP 201609 赛题训练

CCF-CSP 201709 赛题训练

CCF-CSP 202203 赛题训练

CCF-CSP 201909 赛题训练