ccfcsp202312


202312-1 仓库规划


西西艾弗岛上共有n个仓库,依次编号为1…n。每个仓库均有一个m维向量的位置编码,用来表示仓库间的物流运转关系。
具体来说,每个仓库i均可能有一个上级仓库j,满足:仓库j位置编码的每一维均大于仓库i位置编码的对应元素。比如编码为(1,1,1)的仓库可以成为(0,0,0)的上级,但不能成为(0,1,0) 的上级。如果有多个仓库均满足该要求,则选取其中编号最小的仓库作为仓库i的上级仓库;如果没有仓库满足条件,则说明仓库i是一个物流中心,没有上级仓库。
现给定n个仓库的位置编码,试计算每个仓库的上级仓库编号。

#include <bits/stdc++.h>
using namespace std;
bool cmp(vector<int> a1, vector<int> a2, int len) {
    for (int i = 0; i < len; i++) {
        if (a1[i] >= a2[i])
            return false;
    }
    return true;
}
int main(){
    int n,m;
    cin>>n>>m;
    vector<vector<int>> vec(n,vector<int>(m,0));
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>vec[i][j];
        }
    }
    for(int i=0; i<n; i++) {
        bool isFind = false;
        for (int j = 0; j < n; j++) {
            if (cmp(vec[i], vec[j], m)) {
                cout << j + 1 << endl;
                isFind = true;
                break;
            }
        }
        if (isFind == false)
            cout << 0 << endl;
    }
    return 0;

}

202312-2 因子化简


小P同学在学习了素数的概念后得知,任意的正整数n都可以唯一地表示为若干素因子相乘的形式。如果正整数n有m个不同的素数因子p1,P2,…,Pm,则可以表示为:n=pxpx…xpm。
小P认为,每个素因子对应的指数t;反映了该素因子对于几的重要程度。现设定一个阈值k,如果某个素因子p;对应的指数t;小于k,则认为该素因子不重要,可以将书项从几中除去;反之则将p;项保留。最终剩余项的乘积就是n简化后的值,如果没有剩余项则认为简化后的值等于1。
试编写程序处理q个查询:
每个查询包含两个正整数n和k,要求计算按上述方法将n简化后的值。

#include<bits/stdc++.h>
using namespace std;
bool isPrime(int num){
    if (num < 2) return false;
    // 检查从2到num的平方根的整数是否能整除num
    for (int i = 2; i * i <= num; i++) {
        if (num % i == 0) return false; // 如果能被整除,则num不是素数
    }
    return true; // 如果以上都不满足,则num是素数
}
int main(){
    int q;
    cin>>q;
    for(int i=0;i<q;i++) {
        long long n, k;
        cin >> n >> k;
        unordered_map<long long, int> map;
        int index=2;
        while (n!=1) {
            for (int j = index; j <= n; j++) {
                if (isPrime(j) && n % j == 0) {
                    n /= j;
                    map[j]++;
                    index=j;
                    break;
                }
            }
            if(isPrime(n)){
                map[n]++;
                break;
            }
        }
        long long num=1;
        for (auto it: map){
            if(it.second>=k){
                num*=pow(it.first,it.second);
            }
        }
        cout<<num<<endl;
    }
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    while(n--){
        long long a, b;
        int k;
        cin >> a >> k;
        unordered_map<int, int> map;
        b = a;
        for(int i = 2; i <= a && i <= b;){
            if(b % i == 0){
                map[i]++;
                b /= i;
            }else
                i++;
        }
        for(auto it : map){
            while(it.second != 0 && it.second < k){
                a /= it.first;
                it.second--;
            }
        }
        cout << a << endl;
    }
    return 0;
}

202312-3 树上搜索


小C观察了事先收集到的数据,并加以统计,得到了一个名词属于各个类别的可能性大小的信息。具体而言,每个类别都可以赋予一个被称为权重的值,值越大,说明一个名词属于该类别的可能性越大。由于每次向用户的询问可以获得两种回答,小C联想到了二分策略。他设计的策略如下:
1.对于每一个类别,统计它和其全部后代类别的权重之和,同时统计其余全部类别的权重之和,并求二者差值的绝对值, 计为w;
2.选择w最小的类别,如果有多个,则选取编号最小的那一个,向用户询问名词是否属于该类别;
3.如果用户回答“是”,则仅保留该类别及其后代类别,否则仅保留其余类别;
4.重复步骤1,直到只剩下一个类别,此时即可确定名词的类别。
小C请你帮忙编写一个程序,来测试这个策略的有效性。你的程序首先读取到所有的类别及其上级次级关系,以及每个类别的权重。你的程序需要测试对于被归类到给定类别的名词,按照上述策略提问,向用户提出的所有问题。

#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> tree;
vector<long long> wi,tmp;
set<int> no,yes;
void dfs(int index){//深度优先搜索
    yes.insert(index);
    for(int i:tree[index]){
        if(no.find(i)==no.end()){
            dfs(i);
            wi[index]+=wi[i];//更新当前节点的权重,当前节点的权重等于当前节点的权重加上子节点的权重
        }
    }
}
int getMinIdx(int index){
    int minDiffIndex = 1;
    long long minDiff = LLONG_MAX;
    for(int i:yes){
        long long diff = abs(wi[index] - 2 * wi[i]);
        if(diff < minDiff){
            minDiff = diff;
            minDiffIndex = i;
        }
    }
    return minDiffIndex;
}
bool check(int minDiffIndex,int targetIndex){
    if(minDiffIndex == targetIndex)
        return true;
    for(int i : tree[minDiffIndex]){
        if(no.find(i)!=no.end())
            continue;
        if(check(i,targetIndex))
            return true;
    }
    return false;
}
int main(){
    int n,m,fath;
    cin>>n>>m;
    tree.resize(n+1);
    tmp.resize(n+1);
    for(int i=1;i<=n;i++){
        cin>>tmp[i];
    }
    for(int i=2;i<=n;i++){
        cin>>fath;
        tree[fath].push_back(i);
    }

    while(m--){
        int targetIndex;
        cin>>targetIndex;
        no.clear();
        int index=1;
        while(true){
            wi=tmp;
            yes.clear();
            dfs(index);
            if(yes.size()==1){
                break;
            }
            int minDiffIndex = getMinIdx(index);
            // 如果目标节点在子树中,更新当前节点;否则,将该节点添加到不可访问集合中
            if (check(minDiffIndex, targetIndex)) {
                index = minDiffIndex; // 如果目标节点在子树中,更新当前节点,用于下一次搜索
            }
            else {
                no.insert(minDiffIndex); // 否则,将该节点添加到不可访问集合中
            }
            cout<<minDiffIndex<<" ";
        }
        cout<<endl;
    }
    return 0;
}

202312-4 宝藏


西西艾弗岛上埋藏着一份宝藏,小C根据藏宝图找到了宝藏的位置。藏有宝藏的箱子被上了锁,旁边写着一些提示:
给定n条指令,编号为1~n,其中每条指令都是对一个双端队列的操作,队列中的元素均为2x2的矩阵;
在某些时刻,某一条指令可能会改变;
在某些时刻,密码可以由以下方式计算:对于给定的指令区间[l,r],对初始为空的队列依次执行第l~r条指令,将得到的队列里的所有矩阵从头到尾相乘,并将乘积矩阵中的所有元素对 998244353取模,得到的矩阵即为密码;特别地,若队列为空,则密码为单位矩阵;如果能分别计算出这些时刻的密码,将能够打开箱子的锁,从而获得宝藏。
经过小C的观察,每条指令的形式均为以下三种之一:
1.给定2x2的矩阵A,将A插入队列的头部; 2.给定2x2的矩阵B,将B插入队列的尾部; 3.若队列非空,删除队列中最晚被插入的矩阵。
小C将所有的时刻发生的事件均记录了下来。具体地,共有m个时刻,每个时刻可能会发生两种事件:1.第i条指令改变,改变后的指令仍为以上三种形式之一;
2.给定指令区间[I,川],求依次执行第I~r条指令得到的密码。
由于小C并不会这个问题,他向你发起了求助。你需要帮助小C求出所有类型为2的事件所对应的密码。

暴力35分解

#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> instruction;//记录指令
deque<vector<long long>> matrix;//记录矩阵
deque<int> st;//记录矩阵最晚插入
void Execute(int l, int r){
    st.clear();
    matrix.clear();
    for(int i = l; i <= r; i++){
        if(instruction[i][0] == 1){
            st.push_front(instruction[i][0]);
            matrix.push_front({instruction[i][1],instruction[i][2],instruction[i][3],instruction[i][4]});
        }else if(instruction[i][0] == 2){
            st.push_front(instruction[i][0]);
            matrix.push_back({instruction[i][1],instruction[i][2],instruction[i][3],instruction[i][4]});
        }else if(instruction[i][0] == 3 && matrix.size()){
            if(st.front() == 1){
                matrix.pop_front();
                st.pop_front();
            }else if(st.front() == 2){
                matrix.pop_back();
                st.pop_front();
            }
        }
    }
    if(matrix.size() == 0){ //很坑的一点,队列为空时取单位矩阵
        cout << "1 0 0 1" << endl;
        return;
    }
    while(matrix.size() > 1){
        vector<long long> tmp = matrix.front();
        matrix.pop_front();
        long long a, b, c, d;
        a = (tmp[0]*matrix[0][0])%998244353 + (tmp[1]*matrix[0][2])%998244353;
        b = (tmp[0]*matrix[0][1])%998244353 + (tmp[1]*matrix[0][3])%998244353;
        c = (tmp[2]*matrix[0][0])%998244353 + (tmp[3]*matrix[0][2])%998244353;
        d = (tmp[2]*matrix[0][1])%998244353 + (tmp[3]*matrix[0][3])%998244353;
        matrix[0][0] = a%998244353;
        matrix[0][1] = b%998244353;
        matrix[0][2] = c%998244353;
        matrix[0][3] = d%998244353;
    }
    for(int i = 0;i < 4; i++)
        cout << matrix[0][i]%998244353 << " ";
    cout << endl;
}
int main(){
    int n, m;
    cin >> n >> m;
    int u, v;
    while(n--){
        cin >> v;
        if(v == 1 || v == 2){
            int a, b, c, d;
            cin >> a >> b >> c >> d;
            instruction.push_back({v, a, b, c, d});
        }else if(v == 3){
            instruction.push_back({v, 0, 0, 0, 0});
        }
    }
    while(m--){
        cin >> u;
        if(u == 1){
            int i;
            cin >> i >> v;
            if(v == 1 || v == 2){
                instruction[i - 1][0] = v;
                cin >> instruction[i - 1][1] >> instruction[i - 1][2] >> instruction[i - 1][3] >> instruction[i - 1][4];
            }else if(v == 3){
                instruction[i - 1][0] = 3;
            }
        }else if(u == 2){
            int l, r;
            cin >> l >> r;
            Execute(l - 1, r - 1);
        }
    }
    return 0;
}

202312-5 彩色路径


暴力20分解

#include <bits/stdc++.h>
using namespace std;
#define N 5000
vector<int> C(100);//图中每个节点的颜色标签
vector<int> U(N);//每条有向边的起点
vector<int> V(N);//每条有向边的终点
vector<int> D(N);//每条有向边的长度
vector<pair<int, int>> G[N];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n, m, l, k;
    cin >> n >> m >> l >> k;
    vector<vector<int>> dp(n, vector<int>(l, INT_MIN));//dis[i][j] 表示经过j条边,最终到达i号节点的最长路的长度。
    dp[0][0] = 0;
    for (int i = 0; i < n; i++) {
        cin >> C[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> U[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> V[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> D[i];
        G[U[i]].push_back({V[i], D[i]});
    }
    for (int u = 0; u < n - 1; u++){ //u表示起点
        for (auto tem: G[u]) {
            int v = tem.first, w = tem.second;//v表示终点,w表示u到v的边长
            for (int i = 1; i < l; i++) {
                if (dp[u][i - 1] == INT_MIN)
                    continue;
                dp[v][i] = max(dp[v][i], dp[u][i - 1] + w);
            }
        }
    }
    sort(dp[n - 1].rbegin(), dp[n - 1].rend());
    cout << dp[n - 1][0];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值