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

news/2024/6/17 5:26:51 标签: 算法, c++, 数据结构

第一题:灰度直方图

解题思路:哈希查找

#include<iostream>
#include<cstring>

using namespace std;

const int N = 610;
int a[N];
int n , m , l;

int main()
{
	memset(a , 0 , sizeof a);
	cin >> n >> m >> l;
	for(int i = 0;i < n;i ++)
		for(int j = 0;j < m;j ++)
		{
			int x;
			cin >> x;
			a[x] ++;
		}
	
	for(int i = 0;i < l;i ++)
		cout << a[i] << " ";
	
	return 0;
}

第二题:邻域均值

解题思路:

二维前缀和

#include<iostream>
#include<cstring>

using namespace std;

const int N = 610;
int s[N][N];
int n , l , r , t;

int main()
{
    memset(s , 0 , sizeof s);
    cin >> n >> l >> r >> t;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= n;j ++)
        {
            int x;
            cin >> x;
            s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + x;
        }

    int res = 0;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= n;j ++)
        {
            int x1 = max(1 , i - r) , y1 = max(1 , j - r);
            int x2 = min(n , i + r) , y2 = min(n , j + r);
            int sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
            int cnt = (x2 - x1 + 1) * (y2 - y1 + 1);

            if(sum <= t * cnt) res ++;
        }
    cout << res << endl;
    return 0;
}

第三题:DHCP服务器

解题思路:模拟+读题

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;

int n , tdef , tmax , tmin;
string h; // 本机名称

struct IP
{
    int st; // 0表示未分配、1表示待分配、2表示占用、3表示过期
    string owner; // 未分配状态没有占用者
    int t; // 待分配和占用状态拥有一个大于零的过期时刻
}ip[N];

int get_ip_d(string c)
{
    for(int i = 1;i <= n;i ++)
        if(ip[i].owner == c) return i;
    return 0;
}

int get_ip(int state)
{
    /*
    若没有,则选取最小的状态为未分配的 IP 地址
    若没有,则选取最小的状态为过期的 IP 地址
    */
    for(int i = 1;i <= n;i ++)
        if(ip[i].st == state) return i;

    return 0;
}

void update(string send)
{
    /*
    若不是,则找到占用者为发送主机的所有 IP 地址,
    对于其中状态为待分配的,将其状态设置为未分配,并清空其占用者,清零其过期时刻,处理结束
    */
    for(int i = 1;i <= n;i ++)
        if(ip[i].owner == send) 
        {
            if(ip[i].st == 1)
            {
                ip[i].st = 0;
                ip[i].owner = "";
                ip[i].t = 0;
            }

        }
}

void change(int tc)
{
    /*
    在到达该过期时刻时,若该地址的状态是待分配,则该地址的状态会自动变为未分配,
    且占用者清空,过期时刻清零;否则该地址的状态会由占用自动变为过期,且过期时刻清零。
    */

    for(int i = 1;i <= n;i ++)
        if(ip[i].t && ip[i].t <= tc)
        {
            if (ip[i].st == 1)
            {
                ip[i].st = 0;
                ip[i].owner = "";
                ip[i].t = 0;
            }
            else
            {
                ip[i].st = 3;
                ip[i].t = 0;
            }
        }
}

int main()
{
    cin >> n >> tdef >> tmax >> tmin >> h;
    int q;
    cin >> q;
    while(q --)
    {
        // <发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
        string send , get , type;
        int x , tc , te;
        cin >> tc >> send >> get >> type >> x >> te;
        if(get != h && get != "*") 
        {
            // 判断接收主机是否为本机,或者为 *,若不是,则判断类型是否为 Request,若不是,则不处理;
            if(type != "REQ") continue; 
        }
        // 若类型不是 Discover、Request 之一,则不处理
        if(type != "REQ" && type != "DIS") continue;
        // 若接收主机为 *,但类型不是 Discover,或接收主机是本机,但类型是 Discover,则不处理。
        if(get == "*" && type != "DIS" || get == h && type == "DIS") continue;


        change(tc);
        // discover 报文
        if(type == "DIS")
        {
            int k = get_ip_d(send);
            if(!k) k = get_ip(0);
            if(!k) k = get_ip(3);
            if(!k) continue;

            // 将该 IP 地址状态设置为待分配,占用者设置为发送主机
            ip[k].st = 1 , ip[k].owner = send;
            // 若报文中过期时刻为 0 ,则设置过期时刻为 t+tdef
            if(!te) ip[k].t = tc + tdef;
            else
            {
                int w = te - tc;
                w = min(w , tmax) , w = max(w , tmin);
                ip[k].t = w + tc;
            }
            cout << h << " " << send << " OFR " << k << " " << ip[k].t << endl;
        }
        else
        {
            if(get != h) 
            {
                update(send);
                continue;
            }
            if(!(x <= n && x >= 1 && ip[x].owner == send))
            {
                cout << h << " " << send << " NAK " << x << " " << 0 << endl;
                continue;
            }
            // 无论该 IP 地址的状态为何,将该 IP 地址的状态设置为占用
            ip[x].st = 2;
            if (!te) ip[x].t = tc + tdef;
            else
            {
                int w = te - tc;
                w = max(w , tmin), w = min(w, tmax);
                ip[x].t = tc + w;
            }
            cout << h << " " << send << " ACK " << x << " " << ip[x].t << endl;
        }
    }
    return 0;
}

第四题:校门外的树

解题思路:
设 f[i] 为用了前i个障碍点的所有方案, 来做状态划分

设 j 为从 0−i 的每个间断点 
f[i]=(f[0]∗cnt1+f[1]∗cnt2+…+f[j]∗cnt3+…+f[i−1]∗cnt(i−1))
首先,我们知道f[0],f[1],....f[i−1]
, 那重点就在求cnt数组

cnt数组不是一成不变的, 他牵扯到 i 和 j 的选值,我们要求的是 a[i]−a[j] 对应的cnt值, 还要减去重复计数,处理一下约数数组cnt后, 对每次循环遍历每个对应的约数数组cnt求去掉重复计数后的数量,开一个布尔数组记录一下当前循环已经用过了哪些约数即可

#include<iostream>
#include<cstring>
#include<unordered_map>
#include<vector>

using namespace std;

const int N = 1010 , M = 1e5 + 10 , mod = 1e9 + 7;
int n;
int a[N] , f[N];
unordered_map<int , vector<int>>mp;
bool st[M];

int main()
{
    for(int i = 1;i < M;i ++)
        for(int j = i * 2;j < M;j += i)
            mp[j].push_back(i); // 枚举因数
    cin >> n;
    for(int i = 0;i < n;i ++) cin >> a[i];
    f[0] = 1;
    for(int i = 1;i < n;i ++)
    {
        memset(st , 0 , sizeof st);
        for(int j = i - 1;j >= 0;j --)
        {
            int d = a[i] - a[j] , cnt = 0;
            for(int k : mp[d])
                if(!st[k])
                {
                    cnt ++;
                    st[k] = true;
                }
            st[d] = true;
            f[i] = (f[i] + (long long)f[j] * cnt) % mod;
        }
    }
    cout << f[n - 1] << endl;
    return 0;
}

第五题:疫苗运输

迪杰斯特拉+扩展欧几里得算法

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 510;
const LL INF = 0x3f3f3f3f3f3f3f3fll;

int n, m;  // n个物流站,m条线路
int len[N];  // 每一条线路的总用时
struct Node {  // 存储线路信息
    int cid;  // 线路id
    int sum;  // 当前线路内的站点pid到起点的距离
    int pid;  // 线路上的站点赋予的pid,从0开始编号(起点为0,但是站点号不一定和编号相同)
};
// ps[ver] = {{1, 100, j}, {4, 150, k}}: 表示经过站点ver的线路有线路1和线路4
// 线路1编号为j的点经过此站点,j距离线路1的起点(编号为0)为100
vector<Node> ps[N];
// line[i][j] = {ver, y}: 表示线路i上编号(pid)为j的站点ver到下一个站点的距离(时间)是y
vector<PII> line[N];
LL dist[N];  // 每辆车最早拿到疫苗的时间, 通过该时间可以更新该线路上其他点最早拿到疫苗的时间
LL ans[N];  // 每个站点最早拿到疫苗的时间
bool st[N];  // dijkstra中的判重数组
// 存储每条线路最早拿到疫苗的点,例如pid[2]=1: 表示线路2最早拿到疫苗的点编号为1(Node中的pid)
int pid[N];

LL exgcd(LL a, LL b, LL &x, LL &y) {  // 求x, y, 使得ax + by = gcd(a, b)
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return d;
}

void dijkstra() {

    memset(dist, 0x3f, sizeof dist);
    for (int i = 0; i < m; i++) {
        int d = 0;
        for (int j = 0; j < line[i].size(); j++) {
            if (line[i][j].x == 1) {  // 如果线路i上的第j个点站点号是1的话,说明可以作为起点
                dist[i] = d;
                pid[i] = j;  // 线路i最早拿到疫苗的站点的编号为j
                break;
            }
            d += line[i][j].y;
        }
    }

    for (int i = 0; i < m; i++) {
        int t = -1;
        for (int j = 0; j < m; j++)
            if (!st[j] && (t == -1 || dist[j] < dist[t]))
                t = j;
        st[t] = true;

        auto &l = line[t];  // l表示线路t
        auto d = dist[t];  // d表示线路t拿到疫苗的最短时间
        // 枚举线路t上的所有点
        for (int j = pid[t], k = 0; k < l.size(); j = (j + 1) % l.size(), k++) {
            // 枚举点上的所有线路
            for (auto &c : ps[l[j].x]) {
                if (st[c.cid]) continue;  // 这个线路的最短时间已经算出来了
                LL a = d, b = len[t];
                LL x = c.sum, y = len[c.cid];
                // 扩展欧几里得算法
                LL X, Y;
                LL D = exgcd(b, y, X, Y);
                if ((x - a) % D) continue;
                X = (x - a) / D * X;
                y /= D;
                X = (X % y + y) % y;
                if (dist[c.cid] > a + b * X) {
                    dist[c.cid] = a + b * X;
                    pid[c.cid] = c.pid;
                }
            }
            d += l[j].y;
        }
    }
}

int main() {

    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++) {
        // cnt: 该路线上站点数目; sum: 该线路上的站点到该线路起点(编号pid为0)的事假
        int cnt, sum = 0;
        scanf("%d", &cnt);
        for (int j = 0; j < cnt; j++) {
            int ver, t;
            scanf("%d%d", &ver, &t);
            ps[ver].push_back({i, sum, j});  // ver在线路i上, 距离线路i的起点是sum,编号为j
            line[i].push_back({ver, t});  // 路线i上多了一个点ver, ver到下一个点的时间是t
            sum += t;
        }
        len[i] = sum;  // 线路i总耗时
    }

    dijkstra();

    // 此时dist数组已经求出来了
    memset(ans, 0x3f, sizeof ans);
    for (int i = 0; i < m; i++) {  // 枚举所有的线路
        if (dist[i] == INF) continue;
        LL d = dist[i];
        for (int j = pid[i], k = 0; k < line[i].size(); j = (j + 1) % line[i].size(), k++) {
            int ver = line[i][j].x;
            ans[ver] = min(ans[ver], d);
            d += line[i][j].y;
        }
    }

    for (int i = 2; i <= n; i++)
        if (ans[i] == INF) puts("inf");
        else printf("%lld\n", ans[i]);

    return 0;
}


http://www.niftyadmin.cn/n/4945499.html

相关文章

国内外医疗器械政策法规网站集合

随着医疗技术的不断发展&#xff0c;医疗器械在现代医疗中扮演着重要的角色。为了确保医疗器械的安全性、有效性和质量&#xff0c;各国纷纷制定了一系列的政策法规来监管医疗器械的研发、生产、销售和使用。这些政策法规的制定和实施对于保障公众健康、促进医疗器械产业的健康…

聊聊springboot tomcat的maxHttpFormPostSize

序 本文主要研究一下spring boot tomcat的maxHttpFormPostSize参数 parseParameters tomcat-embed-core-9.0.37-sources.jar!/org/apache/catalina/connector/Request.java /*** Parse request parameters.*/protected void parseParameters() {parametersParsed true;Para…

JVM——HotSpot的算法细节实现

一、根节点枚举 固定可作为GC Roots的节点主要在全局性的引用&#xff08;如常量或类静态属性&#xff09;与执行上下文&#xff08;如栈帧中的本地变量表&#xff09;中&#xff0c;尽管目标明确&#xff0c;但查找要做到高效很难。现在java应用越来越庞大&#xff0c;光方法区…

微信抢红包代码在手机上可以使用的

在手机上使用微信抢红包代码&#xff0c;可以通过以下步骤实现&#xff1a; 打开手机的应用商店&#xff0c;搜索并下载一个支持Lua编程语言的代码编辑器&#xff0c;比如"LuaEdit"、"ZeroBrane Studio"等。 在编辑器中创建一个新的Lua脚本文件&#xff0c…

【LeetCode 算法】Find the Losers of the Circular Game 找出转圈游戏输家

文章目录 Find the Losers of the Circular Game 找出转圈游戏输家问题描述&#xff1a;分析代码模拟 Tag Find the Losers of the Circular Game 找出转圈游戏输家 问题描述&#xff1a; n 个朋友在玩游戏。这些朋友坐成一个圈&#xff0c;按 顺时针方向 从 1 到 n 编号。从…

【仿写tomcat】四、解析http请求信息,响应给前端,HttpServletRequest、HttpServletResponse的简单实现

思考 在解析请求之前我们要思考一个问题&#xff0c;我们解析的是其中的哪些内容&#xff1f; 对于最基本的实现&#xff0c;当然是请求类型&#xff0c;请求的url以及请求参数&#xff0c;我们可以根据请求的类型作出对应的处理&#xff0c;通过url在我们的mapstore中找到se…

005-Spring 扩展点 :PostProcess

目录 Spring 扩展点 &#xff1a;PostProcess介绍PostProcess大纲文字明细使用方法示例Autowired 功能实现Resource 功能实现 后记 Spring 扩展点 &#xff1a;PostProcess 介绍 Spring 核心做的事情其实很简单就是&#xff1a;控制反转和依赖注入 也就是把 Class 解析为 Bea…

C语言好题解析(二)

目录 递归类型例题1例题2例题3例题4例题5例题6 递归类型 例题1 根据下面递归函数&#xff1a;调用函数Fun(2)&#xff0c;返回值是多少&#xff08; &#xff09;int Fun(int n) {if (n 5)return 2;elsereturn 2 * Fun(n 1); } A.2 B.4 C.8 D.16【答案】 D 【分析】 …