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

第一题:报数

res = [0 for i in range(4)]
n = int(input())
cnt , cnt1 = 0 , 0 # cnt1 记录报的个数
for i in range(1 , 200000):
    if i % 7 == 0 or '7' in str(i):
        res[cnt] += 1
    else:
        cnt1 += 1
    if cnt1 == n:
        break
    cnt = (cnt + 1) % 4
for i in res:
    print(i)

第二题:回收站选址

简单的图论问题

#include
#include

using namespace std;

const int N = 1010;
typedef pair PII;
int n;
int res[10];
mapg;

struct node
{
    int a , b;
}nodes[N];

int main()
{
    cin >> n;
    for(int i = 0;i < n;i ++)
    {
        int a, b;
        cin >> a >> b;
        g[{a , b}] = true;
        nodes[i] = {a , b};
    }
    
    for(int i = 0;i < n;i ++)
    {
        int a = nodes[i].a , b = nodes[i].b;
        bool f = false;
        if(g[{a , b}])
        {
            if(g[{a + 1 , b}] && g[{a ,b + 1}] && g[{a - 1 , b}] && g[{a , b - 1}]) f = true;
        }
        if(f) 
        {
            int cnt = 0;
            if(g[{a + 1 , b + 1}]) cnt ++;
            if(g[{a + 1 , b - 1}]) cnt ++;
            if(g[{a - 1 , b + 1}]) cnt ++;
            if(g[{a - 1 , b - 1}]) cnt ++;
            res[cnt] ++;
        }
    }
    for(int i = 0;i <= 4;i ++)
        cout << res[i] << endl;
    
    return 0;
}

第三题:化学方程式

解题思路:

(让我想起高中时期的化学)

题目就是检查化学式是否配平,等式两边两个哈希表,哈希表中存储每一个元素的个数和这个元素本身。

使用递归求解可能有括号的化学式,角标相当于乘积。

#include
#include
#include
#include

#define x first
#define y second

using namespace std;

typedef unordered_map MPSI;

MPSI dfs(string &str , int &u)
{
    MPSI res;
    while(u < str.size())
    {
        if(str[u] == '(') 
        {
            u ++; // 过滤掉'('
            auto t = dfs(str , u);
            u ++; // 过滤掉')'
            int cnt = 1 , k = u;
            // 计算角标
            while(k < str.size() && isdigit(str[k])) k ++;
            if(k > u)
            {
                cnt = stoi(str.substr(u , k - u));
                u = k;
            }
            for(auto c : t)
                res[c.x] += c.y * cnt;
        }
        else if(str[u] == ')') break;
        else // 内部元素
        {
            int k = u + 1;
            while(k < str.size() && str[k] >= 'a' && str[k] <= 'z') k ++;
            auto key = str.substr(u , k - u);
            u = k;
            int cnt = 1;
            while(k < str.size() && isdigit(str[k])) k ++;
            if(k > u) 
            {
                // 括号内部元素有角标
                cnt = stoi(str.substr(u , k - u));
                u = k;
            }
            res[key] += cnt;
        }
    }
    return res;
}

MPSI work(string str)
{
    MPSI res;
    for(int i = 0;i < str.size();i ++)
    {
        int j = i + 1;
        while(j < str.size() && str[j] != '+') j ++;
        
        // 以+号分隔进行枚举
        auto item = str.substr(i , j - i);
        i = j;
        int cnt = 1 , k = 0;
        while(k < item.size() && isdigit(item[k])) k ++;
        // 截取系数
        if(k) cnt = stoi(item.substr(0 , k));
        // 解析括号
        auto t = dfs(item , k);
        for(auto c : t)
            res[c.x] += c.y * cnt;
    }
    return res;
}

int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        string s;
        cin >> s;
        int k = s.find("=");
        auto left = work(s.substr(0 , k)) , right = work(s.substr(k + 1));
        if(left == right) puts("Y");
        else puts("N");
    }
    return 0;
}

第四题:区块链

解题思路:

首先使用邻接表存图,然后使用优先队列对于每一条查询数据进行排序

链表如何去存?

使用二维数组进行存储,对于需要更新的内容,我们将其拷贝到最后,使该节点指向这个链表,即可完成更改别的节点的同时不改变这个节点。

#include
#include
#include
#include
#include
#include

using namespace std;

const int N = 510 , M = 2e4 + 10;
typedef vector VI;
int h[M] , ne[M] , e[M] , idx = 0;
int n , m , w , q;
vectorg; // 存储所有列表
int node[M]; // 链表的编号

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

struct Op
{
    // t时间 id编号 pid从哪个节点过来的 hid过来的链表的编号
    int t , id , pid , hid;
    
    // priority_queue默认大根堆,因此需要重载<
    bool operator < (const Op &r) const
    {
        // 考虑什么情况当前元素要排到下一个元素的后面
        return t > r.t;
    }
};

priority_queue heap;

void eval()
{
    auto t = heap.top();
    heap.pop();
    
    // a 堆顶元素对应的列表 b 新链表
    auto &a = g[node[t.id]] , &b = g[t.hid];
    if(b.size() > a.size() || b.size() == a.size() && b.back() < a.back())
    {
        // 当前链表id变为传回来的列表id
        node[t.id] = t.hid;
        for(int i = h[t.id];~i;i = ne[i])
            if(e[i] != t.pid && e[i] != t.id)
                heap.push({t.t + w , e[i] , t.id , t.hid});
    }
}

int main()
{
    cin >> n >> m;
    g.push_back({0});
    memset(h , -1 , sizeof h);
    while(m --)
    {
        int a , b;
        cin >> a >> b;
        // scanf("%d %d" ,&a ,&b);
        add(a , b) , add(b , a);
    }
    
    cin >> w >> q;
    getchar();
    while(q --)
    {
        string s;
        getline(cin , s);
        
        stringstream ss(s);
        int a[3] , cnt = 0;
        while(ss >> a[cnt]) cnt ++;
        if(cnt == 3) // 添加块
        {
            // 当前有操作并且第一个操作时间小于当前的时间
            while(heap.size() && heap.top().t <= a[1]) eval();
            
            // 先复制当前链表
            g.push_back(g[node[a[0]]]);
            // 当前链表已经放置最后
            g.back().push_back(a[2]);
            // 当前链表已经在最后
            node[a[0]] = g.size() - 1;
            for(int i = h[a[0]];~i;i = ne[i])
                if(e[i] != a[0]) // 判断自环
                    heap.push({a[1] + w , e[i] , a[0] , node[a[0]]});
        }
        else // 查询链表
        {
            // 进行完之前的所有操作
            while(heap.size() && heap.top().t <= a[1]) eval();
            cout << g[node[a[0]]].size() << " ";
            for(auto x : g[node[a[0]]]) 
                cout << x << " ";
            cout << endl;
        }
    }
    return 0;
}

第五题:魔数

python自带大数库,然后就直接模拟就行 (肯定超时,这测了快5分钟才出来结果)25分

n , q = map(int , input().split())
U = [314882150829468584 , 427197303358170108 , 1022292690726729920,
     1698479428772363217, 2006101093849356424]
mod = 2009731336725594113
start = [i for i in range(n + 1)]
for _ in range(q):
    l , r = map(int , input().split())
    s = sum((start[i] % mod) % 2019 for i in range(l , r + 1))
    print(s)
    t = s % 5
    for i in range(l , r + 1):
        start[i] = start[i] % mod * U[t] % mod

你可能感兴趣的:(ccf,csp,算法,数据结构,c++)