第一题:未初始化警告
比较简单
题目背景
一个未经初始化的变量,里面存储的值可能是任意的。因此直接使用未初始化的变量,比如将其赋值给另一个变量,并不符合一般的编程逻辑。代码中出现这种情况,往往是因为遗漏了初始化语句、或是打错了变量名。对代码中使用了未初始化变量的语句进行检查,可以方便地排查出代码中的一些隐秘 Bug。
问题描述
考虑一段包含 k 条赋值语句的简单代码。该段代码最多使用到 n 个变量,分别记作 a1,a2,⋯,an;该段代码使用的常量均记作 a0。
第 i 条(1≤i≤k)赋值语句为 axi=ayi,满足 1≤xi≤n、0≤yi≤n,表示将 ayi 的值赋给变量 axi。其中 axi 被称为该赋值语句的左值,一定是个变量;ayi 被称为右值,可以是一个常量或变量。
对于任意一条赋值语句 axi=ayi,如果右值 ayi 是一个变量,则其应该在此之前被初始化过。
具体来说,如果变量 ayi 在前 i−1 条赋值语句中做为左值出现过,即存在 j<i 满足 xj=yi(这里无需考虑第 j 条赋值语句本身是否也有右值未初始化的问题),我们就认为在第 i 条赋值语句中 ayi 已被初始化;
否则,我们认为该条语句存在右值未初始化的问题。
按照上述规则,试统计给定的代码中,有多少条赋值语句右值未被初始化。
输入格式
输入的第一行包含空格分隔的两个正整数 n、k,分别表示变量的数量和赋值语句的条数。
接下来输入 k 行,其中第 i 行(1≤i≤k)包含空格分隔的两个正整数 xi、yi,表示第 i 条赋值语句。
输出格式
输出一个整数,表示有右值未被初始化问题的赋值语句条数。
样例输入
10 7
1 2
3 3
3 0
3 3
6 2
2 1
8 2
我的赛时代码:
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<vector>
using namespace std;
int main()
{
int n=0,k=0,x[100010]={0},y[100010]={0},t=0,sum=0;
int hash[100010]={0};
scanf("%d %d",&n,&k);
for(int i=0;i<k;i++)
{
scanf("%d %d",&x[i],&y[i]);
if(hash[y[i]]>0||y[i]==0)
{
sum++;
}
hash[x[i]]++;
}
printf("%d",k-sum);
return 0;
}
第二题:出行计划
最后复杂程度不会降,只拿了70分
问题描述
最近西西艾弗岛上出入各个场所都要持有一定时限内的核酸检测阴性证明。
具体来时,如果在 t 时刻做了核酸检测,则经过一段时间后可以得到核酸检测阴性证明。这里我们假定等待核酸检测结果需要 k 个单位时间,即在 t+k 时刻可以获得结果。如果一个场所要求持 24 个单位时间内核酸检测结果入内,那么凭上述的核酸检测结果,可以在第 t+k 时刻到第 t+k+23 时刻进入该场所。
小 C 按时间顺序列出接下来的 n 项出行计划,其中第 i 项(1≤i≤n)可以概括为:
ti 时刻进入某场所,该场所需持有 ci 个单位时间内的核酸检测结果入内,其中 0<ci≤2×105。
为了合理安排核酸检测时间,试根据小 C 的出行计划,回答如下查询:
- 如果在 q 时刻做了核酸检测,有多少项出行计划的核酸检测要求可以得到满足?
这样的查询共有 m 个,分别为 q1,q2,⋯,qm;查询之间互不影响。
输入格式
输入的第一行包含空格分隔的三个正整数 n、m 和 k,分别表示出行计划数目、查询个数以及等待核酸检测结果所需时间。
接下来输入 n 行,其中每行包含用空格分隔的两个正整数 ti、ci,表示一项出行计划;出行计划按时间顺序给出,满足 0<t1≤t2≤⋯≤tn≤2×105。
最后输入 m 行,每行仅包含一个正整数 qi,表示一个查询。m 个查询亦按照时间顺序给出,满足 0<q1<q2<⋯<qm≤2×105。
输出格式
输出共 m 行,每行一个整数,表示对应查询的答案。
样例输入
6 2 10
5 24
10 24
11 24
34 24
35 24
35 48
1
2
我的赛时代码:
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<vector>
using namespace std;
int main()
{
int n,m,k,q,a1,sum=0;
int t[100010],c[100010];
scanf("%d %d %d",&n,&m,&k);
for(int i=0;i<n;i++)
{
scanf("%d %d",&t[i],&c[i]);
}
for(int j=0;j<m;j++)
{
scanf("%d",&q);
for(int i=0;i<n;i++)
{
a1=q+k;
if(t[i]>=a1&&t[i]-a1<c[i])
{
sum++;
}
}
printf("%d\n",sum);
sum=0;
}
return 0;
}
第三题:计算资源调度器
对我个人来说大模拟有点难,只对了2个测试点10分。
题目背景
西西艾弗岛上兴建了一批数据中心,建设了云计算资源平台。小 C 是主管西西艾弗云开发的工程师。西西艾弗云中有大量的计算节点,每个计算节点都有唯一编号。
西西艾弗云分为多个可用区,每个计算节点位于一个特定的可用区。一个可用区中可以有多个计算节点。
西西艾弗云中运行的计算任务分为不同的应用,每个计算任务都有一个应用与之对应,一个应用中可能包括多个计算任务。
每个计算任务由一个特定的计算节点执行,下文中计算任务“运行在某可用区上”意即“运行在某可用区的计算节点上”。
不同的计算任务对运行的计算节点的要求不尽相同。有的计算任务需要在指定可用区上运行,有的计算任务要和其它应用的计算任务在同一个可用区上运行,
还有的希望不要和某个应用的计算任务在同一个计算节点上运行。
对于一个计算任务,执行它的计算节点一旦选定便不再更改;在选定计算节点后,该任务对计算节点的要求就不再被考虑,
即使新安排的计算任务使得此前已有的计算任务的要求被违反,也是合法的。
下图示意性地说明了可用区、计算节点、计算任务之间的关系,同时也说明了应用和计算任务的对应关系。
一开始,小 C 使用了电子表格程序来统计计算任务的分配情况。随着云上的计算节点和计算任务的不断增多,小 C 被这些奇怪的要求搞得焦头烂额,有的时候还弄错了安排,让客户很不满意。
小 C 找到你,希望你能为他提供一个程序,能够输入要运行的计算任务和对节点的要求,结合西西艾弗云的现有计算节点信息,计算出计算任务应该被安排在哪个计算节点上。
问题描述
计算任务对计算节点的要求十分复杂而且又不好描述,你对小 C 表示写程序这件事很为难。于是,小 C 进行了调研,
将这些需求进行了归纳整理,形成了下面这三种标准需求。在提出需求时,必须从这三种标准需求中选取若干种,每种需求只能有一条。选取多种需求意味着要同时满足这些需求。
-
计算节点亲和性
计算任务必须在指定可用区上运行。
-
计算任务亲和性
计算任务必须和指定应用的计算任务在同一可用区上运行。
该要求对计算任务可以运行的可用区添加了限制。不考虑该任务本身,一个可用区若运行有指定应用的任务,则满足要求。
-
计算任务反亲和性
计算任务不能和指定应用的计算任务在同一个计算节点上运行。
该要求对计算任务可以运行的计算节点添加了限制。不考虑该任务本身,一个计算节点若运行有指定应用的任务,则不满足要求。
当要执行的计算任务多起来,计算任务反亲和性的要求可能很难满足。因此在添加计算任务反亲和性要求时,还要指定这个要求是“必须满足”还是“尽量满足”。
小 C 要求你按照如下方法来分配计算节点:按照计算任务的启动顺序,根据要求,依次为每个计算任务选择计算节点。一旦选择了一个计算节点,就固定下来不再变动,
并且在此后的选择中,不再考虑这个计算任务的要求。对每个计算任务,选择计算节点的方法是:
-
过滤阶段
在这个阶段,先根据计算任务的要求,过滤出所有满足要求的计算节点。如果不存在这样的计算节点,并且指定了计算任务反亲和性要求,并且计算任务反亲和性要求是尽量满足的,
那么去掉计算任务反亲和性要求,再过滤一次。如果还不存在,就认为该计算任务的要求无法满足,该计算任务无法分配。 -
排序阶段
在这个阶段,将过滤后的计算节点按照这个方法排序:
- 选择此时运行计算任务数量最少的计算节点;
- 选择编号最小的计算节点。
输入格式
输入的第一行包含两个由空格分隔的正整数 n 和 m,分别表示计算节点的数目和可用区的数目。计算节点从 1 到 n 编号,可用区从 1 到 m 编号;
输入的第二行包含 n 个由空格分隔的正整数 l1,l2,…li,…,ln,表示编号为 i 的计算节点位于编号为 li 的可用区。其中,0<li≤m;
输入的第三行包含一个正整数 g,表示计算任务的组数;
接下来的 g 行,每行包含六个由空格分隔的整数 fi、ai、nai、pai、paai、paari,表示依次启动的一组计算任务的信息,其中:
- fi:表示要接连启动 fi 个所属应用和要求相同的计算任务,其中 fi>0;
- ai:表示这 fi 个计算任务所属应用的编号,其中 0<ai≤Amax(Amax 代表最大应用编号);
- nai:表示计算节点亲和性要求,其中 0≤nai≤m。当 nai=0 时,表示没有计算节点亲和性要求;否则表示要运行在编号为 nai 的可用区内的计算节点上;
- pai:表示计算任务亲和性要求,其中 0≤pai≤Amax。当 pai=0 时,表示没有计算任务亲和性要求;否则表示必须和编号为 pai 的应用的计算任务在同一个可用区运行;
- paai:表示计算任务反亲和性要求,其中 0≤paai≤Amax。当 paai=0 时,表示没有计算任务反亲和性要求;否则表示不能和编号为 paai 的应用的计算任务在同一个计算节点上运行;
- paari:表示计算任务亲和性要求是必须满足还是尽量满足,当 paai=0 时,paari 也一定为 0;否则 paari=1 表示“必须满足”,paari=0 表示“尽量满足”。
计算任务按组输入实际上是一种简化的记法,启动一组 (fi,ai,nai,pai,paai,paari) 和连续启动 fi 组 (1,ai,nai,pai,paai,paari) 并无不同。
输出格式
输出 g 行,每行有 fi 个整数,由空格分隔,分别表示每个计算任务被分配的计算节点的情况。若该计算任务没有被分配,则输出 0;否则输出被分配的计算节点的编号。
样例输入
10 4
1 1 1 1 1 2 2 2 2 2
6
2 1 4 1 2 1
6 1 1 0 1 1
1 2 2 0 0 0
6 1 2 0 2 1
5 2 2 0 1 0
11 3 0 1 3 0
我的赛时代码:
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<vector>
using namespace std;
int k=1;
int main()
{
int n,m,g,f[100],a[100],na[100],pa[100],paa[100],paar[100],l[1000],hash[1000];
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%d",&l[i]);
hash[l[i]]++;
}
scanf("%d",&g);
for(int i=0;i<g;i++)
{
scanf("%d %d %d %d %d %d",&f[i],&a[i],&na[i],&pa[i],&paa[i],&paar[i]);
if(hash[a[i]]==0)
{
for(int j=0;j<f[i];j++)
{
printf("0");
if(j==f[i]-1)
{
printf("0");
}
else
{
printf("0 ");
}
}
printf("\n");
}
else
{
int tt=f[i];
while(f[i]--)
{
if(f[i]==0)
{
printf("%d",k++);
}
else
{
printf("%d ",k++);
}
if(k-1==n)
{
k=1;
}
}
printf("\n");
}
}
return 0;
}
总结:这次我第一次参加ccf认证,最后得了180分,前25%,也算是我都对自身实力的感受。