#158. 提高组CSP-S2025初赛模拟卷4

提高组CSP-S2025初赛模拟卷4

提高组CSP - S2025初赛模拟卷4

一、单项选择题(共15题,每题2分,共计30分;每题有且仅有一个正确选项)

  1. 已知小写字母a的ASCII码为97,下列C++代码的输出结果是( )
#include <iostream>
using namespace std; 
int main() {
char a='a';
a++;
cout<<a;
return 0;
}

{{ select(1) }}

  • a
  • b
  • 97
  • 98
  1. 以下代码段的时间复杂度是()。
void Merge(int a[],int left,int mid,int right){ 
    int temp[right - left+1]; 
    int i=left,j=mid+1,k=0; 
    while (i<=mid && j<=right){ 
        if (a[i]<a[j]) 
            temp[k++] =a[i++];
        else 
            temp[k++] =a[j++];
    } 
    while (i<=mid) 
        temp[k++] =a[i++];
    while (j<=right) 
        temp[k++] =a[j++];
    for (int m=left,n=0;m<=right;m++,n++)
        a[m]=temp[n];
}
void Merge_Sort(int a[],int left,int right){ 
    if(left == right) return;
    int mid =(left + right)/2;
    Merge_Sort(a,left,mid);
    Merge_Sort(a,mid+1,right);
    Merge(a,left,mid, right);
}

{{ select(2) }}

  • O(nlogn)
  • O(n)
  • O(logn)
  • O(n²)
  1. 以下哪个方案可以合理解决或缓解哈希表冲突?() {{ select(3) }}
  • 弃用发生冲突的新元素
  • 用新元素覆盖发生冲突的元素
  • 用新元素覆盖冲突位置的下一个位置
  • 将新元素放置在冲突位置之后的第一个空位
  1. 在数组H[x]中,若存在(i<j)&&(H[i]>H[j]),则称(H[i],H[j])为数组H[x]的一个逆序对。对于序列17,14,11,29,3,16,18,15,其中有()个逆序对。 {{ select(4) }}
  • 13
  • 11
  • 12
  • 14
  1. 以下()操作不属于STL模板优先队列的操作函数。 {{ select(5) }}
  • push
  • pop
  • erase
  • size
  1. 以下选项中,()没有涉及C++语言的面向对象特性。 {{ select(6) }}
  • 在C++中构造一个类或结构体
  • 在C++的排序应用中调用sort函数
  • 在C++中调用用户定义的类成员
  • 在C++中构造来源于同一基类的多个派生子类
  1. (2023)₁₀+(2025)₁₆和以下哪个选项相等?( ) {{ select(7) }}
  • (10252)₁₀
  • (280A)₁₆
  • (24012)₈
  • (24016)₈
  1. 三个互不相等的正整数的最大公约数为20,最小公倍数为20000,那么这样的不同的正整数组的个数为()。 {{ select(8) }}
  • 42
  • 48
  • 50
  • 52
  1. 关于排序算法,下面的说法中哪个是错误的?() {{ select(9) }}
  • 堆排序和桶排序不一样,堆排序是基于比较的
  • 堆排序不是一个稳定的排序算法
  • 堆排序和快速排序在最坏情况下的时间复杂度都是O(n²)
  • 删除堆顶元素,需要交换堆顶元素和最后一个元素,并重新调整
  1. 假设用V=(d1,d2,d3,d4,d5,d6,d7)来表示某无向图的7个顶点的度数,下面给出的哪组V值是非法的?() {{ select(10) }}
  • {5,3,3,3,3,2,2}
  • {3,2,3,2,3,6,3}
  • {2,3,2,3,2,3,3}
  • {1,1,3,4,3,3,3}
  1. 与图论有关的典型算法中不能处理负权值的是( )。 {{ select(11) }}
  • 弗洛伊德算法
  • Tarjan算法
  • SPFA算法
  • 迪杰斯特拉算法
  1. 有如下代码:
#include<iostream>
using namespace std;
const int MAXN=10;
int dp[MAXN][MAXN];
int main()
{
    for (int j=1;j<MAXN;++j)
        dp[0][j]=j; 
    for(int i=1;i<MAXN;++i)
        dp[i][0]=i; 
    for (int i=1;i<MAXN; ++i)
        for (int j=1;j<MAXN; ++j)
            dp[i][j]=dp[i-1][j]+dp[i][j-1];
    cout<<2*dp[8][4]+1<<"\n"; 
    return 0;
}

则程序输出的结果为()。 {{ select(12) }}

  • 2021
  • 2023
  • 2025
  • 2027
  1. 下列选项中,哪个可能是下图的广度优先遍历序列?( ) {{ select(13) }}
  • 1,3,5,7,4,2,6,8,9
  • 9,4,2,1,3,7,5,6,8
  • 1,3,5,7,6,8,9,4,2
  • 9,4,7,2,1,3,5,6,8
  1. 从1到20中任取两个数a和b,a+b不是3的倍数的不同取法有( )种。 {{ select(14) }}
  • 180
  • 126
  • 150
  • 175
  1. 某班级有 n 位同学,编号从1到 n ,联欢晚会抽奖时从1到 n 号中抽出两位同学获得特等奖,现在抽出的两位同学的编号之和为5的概率为1/14,则 n 为()。 {{ select(15) }}
  • 10
  • 9
  • 8
  • 7

二、阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填√,错误填×;除特殊说明外,判断题每题1.5分,选择题每题3分,共计40分)

(1)

01 #include<bits/stdc++.h>
02
03 using namespace std;
04
05 const int N=3e5+5,mod=1e9+7;
06 int n,m,a[N],sum[N],lsh[N],f[N];
07 inline int mod_add(int x,int y){
08     x+=y;
09     return x>=mod?x-mod:x;
10 }
11 struct BIT {
12     int c[N];
13     inline void modify(int x,int k){
14         while (x<=m){
15             c[x]=mod_add(c[x],k);
16             x+=(x&-x);
17         }
18     }
19     inline int query(int x){
20         int res=0;
21         while(x){
22             res=mod_add(res,c[x]);
23             x-=(x&-x);
24         }
25         return res;
26     }
27 }odd,even;
28
29 signed main()
30     cin>>n;
31     for (int i=1;i<=n; i++)
32         cin>>a[i];
33     for(int i=1;i<=n;i++)
34         sum[i]=mod_add(sum[i-1],a[i]);
35     for(int i=1;i<=n;i++)
36         lsh[++m]=sum[i];
37     lsh[++m]=0;
38     sort(lsh+1,lsh+m+1);
39     m=unique(lsh+1,lsh+m+1)-lsh-1;
40     even.modify(1,1);
41     for(int i=1;i<=n; i++){
42         int pos = lower_bound(lsh+1,lsh+m+1,sum[i])-lsh;
43         if(sum[i]&1){
44             f[i]=mod_add(odd.query(pos),mod_add(even.query(m),mod-even.query(pos-1)));
45             odd.modify(pos,f[i]);
46         } else {
47             f[i]=mod_add(mod_add(odd.query(m),mod-odd.query(pos-1)),even.query(pos));
48             even.modify(pos,f[i]);
49         }
50     }
51     cout<<f[n]<<endl;
52     return 0;
53 }

对于所有数据,保证1 ≤n ≤3e5,0≤ai<1e9+7。

判断题

  1. 这段代码的空间复杂度为O(N)。 {{ select(16) }}
  • ×
  1. 如果a数组从0开始存的话,这段代码也能输出正确结果。 {{ select(17) }}
  • ×
  1. 如果不进行取模,f[n]可能会大于int的最大值。 {{ select(18) }}
  • ×

选择题

  1. 如果程序输入
4
1 0 0 0 0 0 0 0 0 6 1 5 1 0 0 0 0 0 0 0 4

则程序输出( )。 {{ select(19) }}

  • 1
  • 2
  • 3
  • 4
  1. 对于以下哪种输入,程序输出为0?( ) {{ select(20) }}
  • 1 1
  • 1 2
  • 2 1 1
  • 2 2 2
  1. 如果程序输入
7
1 2 3 4 5 6 7

则程序输出( )。 {{ select(21) }}

  • 1
  • 2
  • 3
  • 4

(2)

01 #include <iostream>
02 #include <algorithm>
03 #include <vector>
04 #include <map>
05 #include <set>
06 #include <numeric>
07 using namespace std;
08 typedef long long ll;
09 typedef vector<int> vi;
10 const int _=5e5*4+1;
11 map<int,vector<int>*>mp;
12 int n,a[_],b[_],last;
13 int o[_];
14 set<int>si;
15 typedef set<int>::iterator sit;
16 sit prei(sit sx) {return --sx; }
17 sit sufi(sit sx) {return ++sx;}
18 class SOL{
19 public:
20     map<int,int>mtr;
21     void radd(int l,int r,int val){
22         mtr[l]+=val,mtr[r+1]-=val;
23     }
24     void rans(){
25         ll ans0=accumulate(a+1,a+n+1,0ll),a=0;
26         for(int i=1;i<=n;i++)
27             cout<<(ans0+=(a+=mtr[i]))<<endl;
28     }
29 }TR;
30 int pre[_],suf[_];
31 bool cmp(int i1,int i2){
32     if(a[i1]==a[i2]) return i1<i2;
33     else return a[i1]<a[i2];
34 }
35 int main(){
36     ios::sync_with_stdio(0),
37     cin.tie(0),cout.tie(0);
38     cin>>n;
39     for(int i=1;i<=n;i++){
40         cin>>a[i],
41         a[i+n]=a[i];
42         if(last==0||a[i]<a[last])
43             last=i+n;
44     }
45     for(int i=1;i<=n;i++)
46         a[i]=a[last-n+i];
47     iota(o+1,o+n+1,1),
48     sort(o+1,o+n+1,cmp);
49     si=set<int>(o+1,o+n+1);
50     for(int i=1;i<=n;i++)
51         si.insert(o[i]),
52         pre[o[i]]=*prei(si.find(o[i])),
53         suf[o[i]]=*sufi(si.find(o[i]));
54
55     for(int i=1;i<=n;i++)
56         ++pre[i];
57     if(a[i]<a[i-1])
58         TR.radd(1,i-pre[i],a[i]);
59     if(a[i]>a[suf[i]])
60         TR.radd(suf[i]-i,suf[i]-pre[i],-a[i]);
61     }
62     TR.rans();
63 }

假设1 ≤n ≤5e5,1 ≤a[i] ≤1e9,回答下列问题。

判断题

  1. 不考虑空间问题,本段代码只需要_>=5e5*2+1,就不会发生数组越界。 {{ select(22) }}
  • ×
  1. 本段代码使用了二阶前缀和。 {{ select(23) }}
  • ×
  1. 在本段代码第58行与第60行中,实际上是向TR加上或者减去一个等比数列。( ) {{ select(24) }}
  • ×

选择题

  1. 该算法的时间复杂度为( )。 {{ select(25) }}
  • O(N²)
  • O(log²N)
  • O(N)
  • O(N log N)
  1. 如果输入如下:
6
171 814 231 366 761 96897

则程序输出的第一个数为()。 {{ select(26) }}

  • 3862
  • 3861
  • 3860
  • 3859
  1. (4分)如果输入如下:
10
99 101 068 2100000000 1000000000 1000000000

则程序输出的第一个数为( )。 {{ select(27) }}

  • 1000000054
  • 2000000053
  • 3000000054
  • 3000000053

(3)

01 #include <bits/stdc++.h>
02 using namespace std;
03 const int N=1e5+5,base=20;
04 int f[1<<base],state[1<<base],cnt[1<<base],a[N];
05 int n,ans;
06 void dfs(int u,int now,int state){
07     f[state] =min(f[state],u-1);
08     if(u>5) return;
09     for(int i=now;i<=base;i++)
10         dfs(u+1,i,(state|(1<<i))&((1<<base)-1));
11 }
12 int main(){
13     memset(f,0x7f, sizeof(f));
14     dfs(1,1,1);
15     for(int mid=1;mid<(1<<base);mid<<=1)
16         for(int i=0;i<(1<<base);i+=(mid<<1))
17             for(int j=0;j<mid;j++)
18                 f[i+j]=min(f[i+j],f[i+j+mid]);
19     for(int i=1;i<(1<<base);i++)
20         if(!(i&1))f[i]=min(f[i],f[i>>1]);
21     scanf("%d",&n);
22     for(int i=1;i<=n;i++){
23         scanf("%d",&a[i]);
24         for(int j=2;j*j<=a[i];j++){
25             if(a[i]%j==0){
26                 int c=0; 
27                 while(a[i]%j==0)++c,a[i]/=j;
28                 state[j]|=(1<<c);
29                 ++cnt[j];
30             }
31         }
32         if(a[i]>1)++cnt[a[i]],state[a[i]]|=2;
33     }
34     for(int i=2;i<=100000;i++){
35         if(cnt[i]!=n) state[i]|=1;
36         ans+=f[state[i]];
37     }
38     printf("%d",ans);
39     return 0;
40 }

对于100%的数据,有1 ≤n ≤10⁵,1<ai≤10⁹。

判断题

  1. 代码第12行运行后,f的所有值都变成-1。 {{ select(28) }}
  • ×
  1. 设x的二进制表示为1000010111010,f[x]在dfs运行完成之后为6。 {{ select(29) }}
  • ×

选择题

  1. 关于第14~18行代码,以下说法中正确的是()。 {{ select(30) }}
  • 对于集合i,如果i的所有非自身子集si能被组合出来,那么f[i]=min(f[si])。
  • 对于集合i,如果i的所有非自身子集si能被组合出来,那么f[i]=max(f[si])。
  • 对于集合i,如果i<<k能被组合出来(1<=k<=20),那么f[i]=min(f[i<<k])。
  • 对于集合i,如果i>>k能被组合出来,且二进制下1的个数相同(1<=k<=20),那么f[i]=min(f[i>>k])-1。
  1. 下列关于第6~10行dfs的描述,正确的是()。 {{ select(31) }}
  • 删去这段代码,程序复杂度不变。
  • 如果改成u>6才return,其他条件不变,则程序输出不变。
  • 如果改成u>4就return,则当base=15时,原程序与新程序执行完dfs后,f数组相同。
  • dfs执行完后,f[0]=-1,但因为后面根本不会访问f[0],所以程序依然输出正确结果。
  1. 关于本段代码,下列说法中正确的是()。 {{ select(32) }}
  • 程序执行完毕后,对于state[i],假设当前值为x,并且有一个a[j]恰好能被i^k整除,那么x&(1<<k - 1)必然非零。
  • f[i]表示在背包下状态为i所需要的物品最小值,例如f[1000111010]=4,因为{1,2,3,4}是一个符合条件的情况。
  • 本段代码的时间复杂度为O(3^base),因为main里面出现了枚举子集的子集。
  • 假如a[1]=30,当读入a[1]并执行代码后,cnt[2]=cnt[4]=cnt[8]=0。

三、完善程序(单选题,每小题3分,共计30分)

(1)题目描述:

农场是一块N×N的方格田地(2≤N≤100),某些相邻的田地之间有道路分隔,外围有高围栏防止牛离开。牛可以在任意相邻田地间自由移动(北、东、南、西),但不喜欢过马路。 农场上有K头牛(1 ≤K ≤100,K ≤N²),每头牛位于不同的田地中。如果两头牛之间要相互访问必须至少穿越一条路,这对牛就被认为是"遥远的"。请计算有多少对牛是"遥远的"。 分析:直接记录牛的方位,用dfs染色,记录每个连通块上牛的个数,并且把它们两两相乘即可。

01 #include <cstdio>
02 #include <iostream>
03 #include <algorithm>
04 #include <cstring>
05 #include <vector>
06 using namespace std;
07 int n,k;
08 int road;
09 int a[105][105][4];
10
11 int color[105][105];
12 int b[105][105];
13 int x,y,x1,y1;
14 int num;
15 int all;
16 long long ans;
17 vector<int> area;
18 int dx[4]={-1,0,1,0};
19 int dy[4]={0,1,0,-1};
20 void dfs(int x,int y)
21 {
22     if(①){
23         return;
24     }
25     if(color[x][y]!=-1){
26         return;
27     }
28     color[x][y]=num;
29     if(b[x][y]==1){
30         all++;
31     }
32     for(int i=0;i<4;i++){
33         if(a[x][y][i]==1){
34             continue;
35         }
36         int xx=x+dx[i];
37         int yy=y+dy[i];
38         dfs(xx,yy);
39     }
40 }
41 int main()
42 {
43     cin>>n>>k>>road;
44     for(int i=1;i<=road;i++){
45         cin>>x>>y>>x1>>y1;
46         if(x==x1){
47             a[x][min(y,y1)][1]=1;
48             ②;
49         } else {
50             a[min(x,x1)][y][2]=1;
51             ③;
52         }
53     }
54     for(int i=1;i<=k;i++){
55         cin>>x>>y;
56         b[x][y]=1;
57     }
58     area.push_back(0);
59     memset(color,-1,sizeof(color));
60     for(int i=1;i<=n;i++){
61         for(int i1=1;i1<=n;i1++){
62             if(④){
63                 all=0;
64                 num++;
65                 dfs(i,i1);
66                 area.push_back(all);
67             }
68         }
69     }
70     for(int i=1;i<num;i++){
71         for(int i1=i+1;i1<=num;i1++){
72             ⑤;
73         }
74     }
75     cout<<ans;
76     return 0;
77 }
  1. ①处应填()。 {{ select(33) }}
  • x<1|| y<1|| x>n|| y>n
  • x>1|| y>1|| x<n|| y<n
  • x>=1&& y>=1&& x<=n && y<=n
  • x1 && y1 && xn && yn
  1. ②处应填()。 {{ select(34) }}
  • a[x][max(y,y1)][0]=1;
  • a[x][max(y,y1)][1]=1;
  • a[x][max(y,y1)][2]=1;
  • a[x][max(y,y1)][3]=1;
  1. ③处应填( )。 {{ select(35) }}
  • a[max(x,x1)][y][0]=1;
  • a[max(x,x1)][y][1]=1;
  • a[max(x,x1)][y][2]=1;
  • a[max(x,x1)][y][3]=1;
  1. ④处应填()。 {{ select(36) }}
  • color[i][i1]!=-1
  • color[i][i1]==-1
  • b[i][i1]==1
  • b[i][i1]!=1
  1. ⑤处应填()。 {{ select(37) }}
  • ans+=area[i]+area[i1];
  • ans+=area[i]-area[i1];
  • ans+=area[i]*area[i1];
  • ans+=area[i]/area[i1];

(2)题目描述:

对n个单词进行加密。加密过程如下。 (i)选择一个英文字母表的排列作为密钥。 (ii)将单词中的a替换为密钥中的第一个字母,b替换为密钥中的第二个字母,以此类推。 例如,以qwertyuiopasdfghjklzxcvbnm作为密钥对cezar加密后,将得到etmqk。请你给出一种构造方式,最初的第ai个单词位于第i位。请你判断这能否实现。如果能,请给出任意一种可行的密钥。考虑使用拓扑排序完成,代码如下。

01 #include <bits/stdc++.h>
02 using namespace std;
03 const int N= 1e2+50;
04 int n, ord[N],in[N];
05 char ans[N],wrd[N][N];
06 vector<int>e[N],s;
07 void add(int x,int y)
08 {
09     for(int i=1;i<=①;i++)
10         if(wrd[x][i]!=wrd[y][i])
11         {
12             e[wrd[x][i]].push_back(wrd[y][i]);
13             if(②)in[wrd[x][i]]=0;
14             if(③)in[wrd[y][i]]=1; 
15             else in[wrd[y][i]]++;
16             return;
17         }
18     if(strlen(wrd[x]+1)>strlen(wrd[y]+1))puts("NE"),exit(0);
19 }
20 void topo()
21 {
22     queue<int>q;
23     for(int i='a'; i<='z';i++)if(!in[i])q.push(i);
24     while(!q.empty())
25     {
26         int u=q.front();
27         q.pop();s.push_back(u);
28         for(auto v:e[u])
29             if(!(--in[v])) q.push(v);
30     }
31 }
32 signed main()
33 {
34     scanf("%d",&n);
35     for(int i='a';i<='z';i++)in[i]=-1;
36     for(int i=1;i<=n;i++)scanf("%s",wrd[i]+1);
37     for(int i=1;i<=n;i++)scanf("%d",ord+i);
38     for(int i=1; i< n; i++)
39         for(④)
40             add(ord[i],ord[i+1]);
41     topo();
42     for(int i='a';i<='z';i++)if(in[i]>0) return puts("NE"),0;puts("DA");
43     int cnt=0;
44     for(auto i:s) ans[i]='a'+cnt++;
45     for(int i='a'; i<='z';i++)
46     {
47         if(!ans[i])printf("%c",⑤);
48         else printf("%c",(char)ans[i]);
49     }
50     return 0;
51 }
  1. ①处应填()。 {{ select(38) }}
  • min(strlen(wrd[x]+1),strlen(wrd[y]+1))
  • max(strlen(wrd[x]+1),strlen(wrd[y]+1))
  • strlen(wrd[x]+1)
  • strlen(wrd[y]+1)
  1. ②处应填()。 {{ select(39) }}
  • in[wrd[x][i]]!=-1
  • in[wrd[x][i]]==-1
  • in[wrd[x][i]]==0
  • in[wrd[x][i]]!=0
  1. ③处应填()。 {{ select(40) }}
  • in[wrd[y][i]]!=-1
  • in[wrd[y][i]]==-1
  • in[wrd[y][i]]==0
  • in[wrd[y][i]]!=0
  1. ④处应填()。 {{ select(41) }}
  • int o=i;o<n;o++
  • int o=i;o<=n;o++
  • int o=i+1;o<n;o++
  • int o=i+1;o<=n;o++
  1. ⑤处应填()。 {{ select(42) }}
  • (char)('z'-cnt--)
  • (char)('z'---cnt)
  • (char)('a'+cnt++)
  • (char)('a'+++cnt)