csp2020提高组初赛

csp2020提高组初赛

ziyuan/2020CSP-S初赛试题.pdf at main · huaziqi/ziyuan (github.com)

一、单选题

  1. 视频内存大小计算。32位真彩色指的是用32位二进制表示一个像素的颜色。一位二进制表示1bit(比特),8bit = 1byte(字节)。byte也就是B嘛,之后就是KB,MB什么的。32位表示一个像素点,就说明一个像素点4byte。之后再按照题目里说的乘起来换算一下就行了。

  2. n个点,e条边,邻接表存图进行深搜求时间复杂度。每个节点和边都会遍历到,所以是O(n+e)

  3. 普通dijkstra的时间复杂度?

#include<iostream>
#include<cstring>
#include<climits>
#include<vector>
using namespace std;

#define inf 2147483647
#define N 100010
#define ll long long

vector<int> v[N];
int n, s, m, dis[N], k, head[N], tot;
int pos;
bool flag[N];

struct
{
    int to, nxt, val;
}e[N * 5];

void add(int u, int v, int w)
{
    e[++ tot].to = v;
    e[tot].nxt = head[u];
    e[tot].val = w;
    head[u] = tot;
}

int main(){
    cin >> n >> m >> s;
    for(int i = 1; i <= m; ++ i){
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
    }
    for(int i = 1; i <= n; ++ i)
        dis[i] = inf;
    dis[s] = 0;
    flag[s] = 0;
    pos = s;
    while(flag[pos] == 0)//看做n个循环
    {
        ll minn = inf;
        flag[pos] = 1;
        for(int i = head[pos]; i; i = e[i].nxt)//要遍历所有的边m
        {
            int t = e[i].to;
            if(!flag[t] && dis[t] > dis[pos] + e[i].val)
                dis[t] = dis[pos] + e[i].val;
        }
        for(int i = 1; i <= n; i ++)
        {
            if(!flag[i] && dis[i] < minn)
            {
                minn = dis[i];
                pos = i;
            }
        }
    }
    for(int i = 1; i <= n; i ++)
        cout << dis[i] << " ";
    
    return 0;
}

总复杂度O(n2+m) 算作n2

二、程序阅读

1、

实际上d[i] + d[j] - (d[i] && d[j])就等于d[i] || d[j].从二进制的角度思考,d[i] + d[j]把相同的位数都多加了一遍,&&将两个数所有相同的位数取过来了,减去以后,就是两个数至少有一者有的位数,也就是 ||。(没听懂?模拟一遍)

(1)属于是出卷人语文没学好,n必须小于1000,否则可能运行错误。

也就是当n大于等于1000时,程序可能发生错误。当n = 1000,数组会到999,可能不会报错。但是当n = 10000是不是就肯定报错了?所以说,可能会运行错误,应该是对的

(2) 举一个反例:当 n = 1,ans = -1

(3)j = 0改成j = i + 1,也就是从i后面开始比较,无法与前面的比较,假如序列是单调递减的,那么ans就永远等于-1,因为无法满足条件 d[ i ] < d[ j ]。

同样举一个例子:当 n = 2,两个数字为2,1,未改变之前答案是3,新程序是-1.

(4)把d[i] < d[j] 改成 d[i] != d[j] 是可以的,因为源程序在枚举时会将一个数对枚举两遍,只不过先后枚举的顺序不同,所以没有区别。

(5)若n为100,输出为127,输入中不可能含有什么?实际上就是开头讲到的这个结论,那个计算式就表示为d[i] || d[j],倘若有一个元素为128,那么ans一定>=128而不是127

(6)又要用到那个二级结论。一个数是否为奇数,取决于他的末尾是0还是1。所以两个数或运算,只要有一个奇数,结果就是奇数。

这题虽然程序看起来很简单,但是要把题目做全对还是要花点功夫的

2、

这个程序是求n个数中第k小的数,第一次看没看出来。

有点像快速排序,加入了随机化,在[L, R]内选择一个数,将大于他的数放到左边,小于他的数放到右边,这两个区间的中间点为 a - 1 与 a。

(1)显然是错的,应该是[L, R]

(2)正确的,因为当循环结束后,a == b,所以二者等价

为什么最后 a == b,因为三个while里,条件都是a < b,运算只有加减1,所以最后只有当 a == b 时才会结束。

(3)答案是ABCD,有点逆天,应该是题目出的有问题。

(4)单调递减时的时间复杂度。手膜一遍样例,可以发现当n = 7, swap执行6次,从模拟的过程可以发现,每一次会将遍历的区间取一半。因为是单调递减,所以交换次数每次是(区间长度/2),所以总次数为n/2 + n/4 + n/8 ... = n

(5)若d[i] = i,那就是单调递增的,每一次会将所有数遍历一遍。每一次又区间减半,所以n + n/2 + n/4 = 2n O(n).

最坏情况下,假如每次rand都抽到区间的右区间,那么a来到最右边,k > a - L,这样每一次分治只会减少一个数,所以时间复杂度为n2.

(6)假如d[i]都为同一个数,因为--b的while条件是d[b] >= d[L],所以每一次a, b都会来到L + 1的位置。每一次规模都减1,所以时间复杂度为n2

3、

双向BFS,大致是从起点和终点同时开始搜索,直到某状态被枚举两次,也就是有交集。

鼠鼠不会,未完待续

三、完善程序

1、

没什么好说的,简单的贪心

2、

posted @   huaziqi  阅读(179)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示