一、单项选择题(共 10 题,每题 2 分,共计 20 分; 每题有且仅有一个正确选项)
\2. 下列属于解释执行的程序设计语言是( )。
A. C
B. C++
C. Pascal
D. Python
答案:D
解析:编译语言 :C/C++、Pascal/Object Pascal(Delphi)
解释性语言 :JavaScript、VBScript、Perl、Python、Ruby、MATLAB
区别就是编译语言要先翻译成中间代码,每执行一次都要翻译一次
\4. 设根节点深度为 0,一棵深度为 h 的满 k(k>1)叉树,即除最后一层无任何
子节点外,每一层上的所有结点都有 k 个子结点的树,共有( )个结点。
A.
\[(k^{h+1}-1)/(k-1) \]B.
\[k^{h-1} \]C.
\[k^h \]D.
\[(k^{h-1})/(k-1) \]答案:A
解析:做得时候是自己画了几棵树带进去,结果选了D
知乎上一位大佬的解释
对于满 k 叉树,第 0 层有 1 个节点,第 1 层有 k 个节点,第 2 层有 k2 个节点,第 3 层有 k3 个节点,……,第 h 层有 kh 个节点。
运用等比数列求和公式,一共有 ![截屏2022-08-14 16.18.27](/Users/hongshengkai/Library/Application Support/typora-user-images/截屏2022-08-14 16.18.27.png)
个节点。
\5. 设某算法的时间复杂度函数的递推方程是 T(n) = T(n - 1) + n(n 为正整数)
及 T(0) = 1,则该算法的时间复杂度为( )。
A. O(log n)
B. O(n log n)
C. O(n)
D. O(n^2)
答案:D
解析:简单推了一下,例如
T(1) = T(0) + 1,T(2) = T(1) + 2,T(3) = T(2) + 3; 以为是O(N), 但是每一个T(i)都要重新算一遍 为什么不加个记忆化捏 T_T
\7. 在一条长度为 1 的线段上随机取两个点,则以这两个点为端点的线段的期望
长度是( )。
A. 1 / 2
B. 1 / 3
C. 2 / 3
D. 3 / 5
答案:B
解析:百度:可以通过几何概型+体积来求。建立一个三维坐标系Oxyz,x轴代表点A位置,y轴代表点B位置,z轴代表线段长度期望,那么长度的期望就是两个四面体拼起来的图形,顶点为(0,0,0),(1,0,0),(0,1,0),(0,0,1)和(1,1,0),(1,0,0),(0,1,0),(1,1,1)。这个几何体的体积为1/3(锥体体积为底面积乘以高再除以3),由于底面积为1,所以高度平均为1/3,即长度期望为1/3。
\8. 关于 Catalan 数 Cn = (2n)! / (n + 1)! / n!,下列说法中错误的是( )。
A. Cn 表示有 n + 1 个结点的不同形态的二叉树的个数。
B. Cn 表示含 n 对括号的合法括号序列的个数。
C. Cn 表示长度为 n 的入栈序列对应的合法出栈序列个数。
D. Cn 表示通过连接顶点而将 n + 2 边的凸多边形分成三角形的方法个数。
答案:A
解析:卡特兰数是……,满足递推式
\[h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n≥2) \]之后出一篇博客来理解好了……
二 、 不定 项选择题(共 5 题,每题 2 分,共计 10 分 ;每题有一个或多个正确选
项,多选或少选均不得分 )
\1.官方 | CCF NOIP竞赛须知 (sohu.com)
\3. 下列关于最短路算法的说法正确的有( )。
A. 当图中不存在负权回路但是存在负权边时,Dijkstra 算法不一定能求出源点到所有点的最短路。
B. 当图中不存在负权边时,调用多次 Dijkstra 算法能求出每对顶点间最短路径。
C. 图中存在负权回路时,调用一次 Dijkstra 算法也一定能求出源点到所有点的最短路。
D. 当图中不存在负权边时,调用一次 Dijkstra 算法不能用于每对顶点间最短路计算。
答案:ABD
解析:dijstra算法不适用于负权图, 没选A, 应该是肯定。
二、问题求解(每题5分,共10分)
2. 方程 ab =(a or b) * (a andb),在a, b都取[0、31]中的整数时,共有______组解。(表示乘法;or表示按位或运算;and表示按位与运算)
解析:
四、阅读程序写结果(共 4 题,每题8 分,共计 32 分)
#include
using namespace std;
string s;
long longmagic(int l, int r) {
long long ans = 0;
for (int i = l; i <= r; ++i) {
ans = ans * 4 + s[i] - 'a' + 1;
}
return ans;
}
int main() {
cin >> s;
int len = s.length();
int ans = 0;
for (int l1 = 0; l1 < len; ++l1) {
for (int r1 = l1; r1 < len; ++r1) {
bool bo = true;
for (int l2 = 0; l2 < len; ++l2) {
for (int r2 = l2; r2 < len; ++r2) {
if (magic(l1, r1) == magic(l2, r2)&& (l1 != l2 || r1 != r2)) {
bo = false;
}
}
}
if (bo) {
ans += 1;
}
}
}
cout << ans << endl;
return 0;
}
输入:abacaba
输出:16
解析:看代码的意思是求有多少对子串是相同的,但是我看漏掉了一个(l1 != l2 || r1 != r2)的条件,结果算出来48.寄
#include
using namespace std;
const int N =110;
bool isUse[N];
int n, t;
int a[N], b[N];
bool isSmall() {
for (int i = 1; i <= n; ++i)
if (a[i] != b[i]) return a[i] < b[i];
return false;
}
boolgetPermutation(int pos) {
if (pos > n) {
return isSmall();
}
for (int i = 1; i <= n; ++i) {
if (!isUse[i]) {
b[pos] = i; isUse[i] = true;
if (getPermutation(pos + 1)) {
return true;
}
isUse[i] = false;
}
}
return false;
}
void getNext() {
for (int i = 1; i <= n; ++i) {
isUse[i] = false;
}
getPermutation(1);
for (int i = 1; i <= n; ++i) {
a[i] = b[i];
}
}
int main() {
scanf("%d%d", &n, &t);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= t; ++i) {
getNext();
}
for (int i = 1; i <= n; ++i) {
printf("%d", a[i]);
if (i == n) putchar('\n'); else putchar('');
}
return 0;
}
输入1:6 10 1 6 4 5 32
输出 1:2 1 3 5 6 4 (3 分)
输入2:6 200 1 5 3 4 26
输出 2:3 2 5 6 1 4 (5 分)
解析:第一个可以手算出来,第二个样例太大了,看大佬说可以用康拓展开,蒟蒻表示先放着…
五、完善程序(共 2 题,每题 14 分,共计 28 分)
\1. 对于一个1到n的排列p(即1到n中每一个数在p中出现了恰好一次),令qi为第i个位置之后第一个比pi值更大的位置,如果不存在这样的位置,则qi =n+1。
举例来说,如果n=5且p为1 5 4 2 3,则q为2 6 6 5 6。
下列程序读入了排列p,使用双向链表求解了答案。试补全程序。(第二空2分,其余3分)
数据范围 1 ≤ n ≤ 105。
#include
using namespace std;
const int N =100010;
int n;
int L[N], R[N],a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
a[x] = i ;
}
for (int i = 1; i <= n; ++i) {
R[i]= i + 1;
L[i] = i - 1;
}
for (int i = 1; i <= n; ++i) {
L[ R[a[i]]] = L[a[i]];
R[L[a[i]]] = R[a[i] ];
}
for (int i = 1; i <= n; ++i) {
cout << R[i]<< " ";
}
cout << endl;
return 0;
}
解析:
其他空都比较好填 ,只有那个
for (int i = 1; i <= n; ++i) {
L[ R[a[i]]] = L[a[i]];
R[L[a[i]]] = R[a[i] ];
}
比较费脑子。题目里说是双向链表
可以看看这道
\2. 一只小猪要买 N 件物品(N 不超过 1000)。
它要买的所有物品在两家商店里都有卖。第 i 件物品在第一家商店的价格是 a[i],在第二家商店的价格是 b[i],两个价格都不小于 0 且不超过 10000。如果在第一家商店买的物品的总额不少于 50000,那么在第一家店买的物品都可以打 95 折(价格变为原来的 0.95 倍)。
求小猪买齐所有物品所需最少的总额。
输入:第一行一个数 N。接下来 N 行,每行两个数。第 i 行的两个数分别代表 a[i],b[i]。
输出:输出一行一个数,表示最少需要的总额,保留两位小数。
试补全程序。(第一空 2 分,其余 3 分)
#include <cstdio>
#include <algorithm>
using namespace std;
const int Inf = 1000000000;
const int threshold = 50000;
const int maxn = 1000;
int n, a[maxn], b[maxn];
bool put_a[maxn];
int total_a,total_b;
double ans;
intf[threshold];
int main() {
//第一部分
scanf("%d",&n);
total_a= total_b = 0;
for(int i = 0; i < n; ++i) {
scanf("%d%d",a + i, b + i);
if(a[i] <= b[i]) total_a += a[i];
elsetotal_b += b[i];
}
ans =total_a + total_b;
total_a= total_b = 0;
for(int i = 0; i < n; ++i) {
if( (1) ) {
put_a[i]= true;
total_a+= a[i];
}else {
put_a[i]= false;
total_b+= b[i];
}
}
if ((2) ) {
printf("%.2f",total_a * 0.95 + total_b);
return0;
}
//第二部分
f[0]= 0;
for(int i = 1; i < threshold; ++i)
f[i]= Inf;
inttotal_b_prefix = 0;
for(int i = 0; i < n; ++i)
if (!put_a[i]) {
total_b_prefix += b[i];
for (int j = threshold - 1; j >= 0; --j) {
if ( (3) >= threshold && f[j] != Inf)
ans = min(ans, (total_a + j +a[i]) * 0.95+ (4) );
f[j] = min(f[j] + b[i], j >= a[i] ? (5) :Inf);
}
}
printf("%.2f",ans);
return0;
}
解析:最后一道的话,能蒙多少算多少,放个大佬的解析
NOIP 2018 提高组初赛试题 题目+答案+简要解析 - lzylzy/kk - 博客园 (cnblogs.com)
orz
标签:return,试题,int,每题,初赛,noip2018,l2,ans,解析 From: https://www.cnblogs.com/huaziqi/p/16586599.html代码分为两个部分。
第一部分是一个贪心,我们假设满足了优惠条件,按照折后价格进行贪心,如果结果满足了优惠条件就直接输出,此时如果放弃某些b商品来买a不会再有更优策略
第二部分是一个dp……策略就是把原先买了b的东西买a以获得折扣
f[i,j]表示前i个物品,在额外在A店花了j元的情况下,购买B店物品花费的最小值。i呢?想想你的01背包是怎么优化的。
3空是一个转移判断条件,tot_a+j+a[i]是在a店话费的总钱数(本来花的钱+前面改了的钱+当前物品价格)
4空表示在b商店买的物品总价, total_b + f[j] - total_b_prefix
5空更新,看看这个商品在a商店买还是b商店买