历年CSP-J初赛真题解析 | 2020年CSP-J初赛阅读程序(16-33)

学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。

附上汇总贴:历年CSP-J初赛真题解析 | 汇总-CSDN博客


#include <cstdlib>
#include <iostream>
using namespace std;

char encoder[26] = {'C', 'S', 'P', 0};
char decoder[26];

string st;

int main() {
    int k = 0;
    for (int i = 0; i < 26; ++i)
        if (encoder[i] != 0) ++k;  //k=3
    for (char x = 'A'; x <= 'Z'; ++x) {  //枚举每一个大写字符
        bool flag = true;
        for (int i = 0; i < 26; ++i)
            if (encoder[i] == x) {
                flag = false;
                break;
            }
        if (flag) {  //如果x未在encoder中出现
            encoder[k] = x;
            ++k;
        }
    } 
    //循环结束encoder = [C,S,P,A,B,D,E,F...]
    for (int i = 0; i < 26; ++i)  
        decoder[encoder[i] - 'A'] = i + 'A';  //d['C']='A' e['A']='C'
    //循环结束decoder = [D,E,A,F,G,H,I,J...]
    cin >> st;
    for (int i = 0; i < st.length(); ++i)
        st[i] = decoder[st[i] - 'A'];
    cout << st;
    return 0;
}

16、输入的字符串应当只由大写字母组成,否则在访问数组时可能越界。( )

【答案】:对

【解析】

decoder的范围是0-26,30行是st[i]-'A',所以st[i]必须是大写字母。

17、若输入的字符串不是空串,则输入的字符串与输出的字符串一定不一样。( )

【答案】:错

【解析】

encoder = [C S P A B D E F G H I J K L M N O Q R T U V W X Y Z]

decoder = [D E A F G H I J K L M N O P Q C R S B T U V W X Y Z]

两个字符列表,从T以后加密和解密都是自己。所以是错误的

18、将第12行的“i < 26”改为“i < 16”,程序运行结果不会改变。( )

【答案】:

【解析】

第13行的目的是求出k=3,改为i<16后,k还是等于3,所以结果不变

19、将第26行的“i < 26”改为“i < 16”,程序运行结果不会改变。( )

【答案】:错

【解析】

如果只求前16个,那后10的decoder的值就会发生变化

20、若输出的字符串为“ABCABCABCA”, 则下列说法正确的是( A )

A.输入的字符串中既有S又有 P

B.输入的字符串中既有 S 又有 B

C.输入的字符串中既有 A 又有P

D.输入的字符串中既有 A 又有 B

【答案】:

【解密】

输出(解密)的字符为A,那就是加密之前是A,输入的字符就应该是加密后的字符。

加密前 = [A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]

加密后 = [C S P A B D E F G H I J K L M N O Q R T U V W X Y Z]

即encoder[A]=C,encoder[B]=S,encoder[C]=P

decoder[C]=A,decoder[S]=B,decoder[P]=C

21、若输出的字符串为“CSPCSPCSPCSP”,则下列说法正确的是( D )

A.输入的字符串中既有P又有 K

B.输入的字符串中既有 J 又有 R

C.输入的字符串中既有 J 又有 K

D.输入的字符串中既有 P 又有 R

加密前 = [A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]

加密后 = [C S P A B D E F G H I J K L M N O Q R T U V W X Y Z]

即encoder[C]=P,encoder[S]=R,encoder[P]=N

decoder[P]=C,decoder[R]=S,decoder[N]=P

#include <iostream>
using namespace std;

long long n, ans;
int k, len;
long long d[1000000];

int main() {
    cin >> n >> k;
    d[0] = 0;
    len = 1;
    ans = 0;
    for (long long i = 0; i < n; ++i) {
        ++d[0];
        for (int j = 0; j + 1 < len; ++j) {
            if (d[j] == k) {  //进位
                d[j] = 0;
                d[j + 1] += 1;
                ++ans;  //只在进位时发生改变,记录进位次数
            }
        }
        if (d[len - 1] == k) {  //高精度加法,进位操作
            d[len - 1] = 0;
            d[len] = 1;
            ++len;  //只在高位进位时发生改变,即记录数字长度
            ++ans;
        }
    }
    cout << ans << endl;
    return 0;
}

假设输入的n是不超过2^62的正整数,k都是不超过10000的正整数,完成下面的判断题和单选题:

22、若k=1, 则输出ans时, len=n。( )

【答案】:错

【解析】

k=1时,len始终为2。所以错误

23、若k>1, 则输出ans时, len一定小于n。( )

【答案】:错

【解析】

n=1时,len等于1,所以错误

24、若k>1, 则输出ans时, k^len一定大于n。( )

【答案】:对

【解析】

k进制下的2位数n(len=2),一定小于k²。如10进制下的2位数,都是小于100的。2进制下的2位数,一定小于4。所以正确

25、若输入的n等于10^15,输入的k为1,则输出等于( )

A.1

B.(10^30-10^15)/2

C.(10^30+10^15)/2

D.10^15

【答案】:D

【解析】

k=1时,len=2,只会在低位(即d[1])进位,所以进位数量和数字大小相同,选D

26、若输入的n等于205,891,132,094,649(即3^30),输入的k为3,则输出等于( B )

A.3^30

B.(3^30-1)/2

C.3^30-1

D.(3^30+1)/2

【答案】:

【解析】

d[0]向d[1]进位,每3次进一位,进位次数(ans)是3^29

d[1]向d[2]进位,每9次进一位,进位次数(ans)是3^28

d[2]向d[3]进位,每3^3次进一位,进位次数(ans)是3^27

...

d[29]向d[30]进位,进位次数(ans)是3^0

求和就是3^29+3^28+3^27+...+3^0,根据等比数列求和公式,等于(3^30-1)/2

27、若输入的n等于100,010,002,000,090,输入的k为10,则输出等于( )

A.11,112,222,444,543

B.11,122,222,444,453

C.11,122,222,444,543

D.11,112,222,444,453

【答案】:D

【解析】

d[0]向d[1]进位,进位次数为10001000200009

d[1]向d[2]进位,进位次数为1000100020000

d[2]向d[3]进位,进位次数为100010002000

d[3]向d[4]进位,进位次数为10001000200

d[4]向d[5]进位,进位次数为1000100020

d[5]向d[6]进位,进位次数为100010002

d[6]向d[7]进位,进位次数为10001000

d[7]向d[8]进位,进位次数为1000100

d[8]向d[9]进位,进位次数为100010

d[9]向d[10]进位,进位次数为10001

d[10]向d[11]进位,进位次数为1000

d[11]向d[12]进位,进位次数为100

d[12]向d[13]进位,进位次数为10

d[13]向d[14]进位,进位次数为1

最后计算为11112222444453

#include <algorithm>
#include <iostream>
using namespace std;

int n;
int d[50][2];
int ans;

void dfs(int n, int sum) {
    if (n == 1) { 
        ans = max(sum, ans);  //希望把n个合并到只剩一个时代价能够最大
        return;
    }
    for (int i = 1; i < n; ++i) {
        int a = d[i - 1][0], b = d[i - 1][1];
        int x = d[i][0], y = d[i][1];
        d[i - 1][0] = a + x;  //枚举相邻的两个元素合并
        d[i - 1][1] = b + y;
        for (int j = i; j < n - 1; ++j)  //抹去第i个元素
            d[j][0] = d[j + 1][0], d[j][1] = d[j + 1][1];
        int s = a + x + abs(b - y);  //合并相邻两个元素的代价
        dfs(n - 1, sum + s);  //回溯法
        for (int j = n - 1; j > i; --j)  //还原第i个元素
            d[j][0] = d[j - 1][0], d[j][1] = d[j - 1][1];
        d[i - 1][0] = a, d[i - 1][1] = b;
        d[i][0] = x, d[i][1] = y;
    }
}

int main() {
    cin >> n;
    for (int i = 0; i < n; ++i)
        cin >> d[i][0];
    for (int i = 0; i < n; ++i)
        cin >> d[i][1];
    ans = 0;
    dfs(n, 0);
    cout << ans << endl;
    return 0;
}

假设输入的n是不超过50的正整数,d[i][0]、d[i][1]都是不超过10000的正整数,完成下面的判断题和单选题:

28、若输入n为0,此程序可能会死循环或发生运行错误。( )

【答案】:错

【解析】

n=0时,整个循环不会执行,不会发生错误

29、若输入n为20,接下来的输入全为0,则输出为0。( )

【答案】:

【解析】

输入全为0时,s为0,sum也为0,所以ans也为0

30、输出的数一定不小于输入的d[i][0]和d[i][1]的任意一个。( 错 )

【答案】:错

【解析】

n=1时,没有合并,ans为0,此时不管d数组中值为多少。ans都会小于等于d数组中的数字,所以错误。

31、若输入的n为20,接下来的输入是20个9和20个0,则输出为( A )。

A.1890

B.1881

C.1908

D.1917

【答案】:B

【解析】

第一次合并的代价是18,第二次合并的代价是27,第三次合并的代价是36,....,最后一次合并的代价是9*20=180。

所以总的代价=9*2+9*3+9*4+...+9*20=1881

32、若输入的n为30,接下来的输入是30个0和30个5,则输出为( )。

A.2000

B.2010

C.2030

D.2020

【答案】:C

【解析】

第一次合并的代价是0,第二次合并的代价是5,第三次合并的代价是10,...,最后一次合并的代价是28*5。

所有总的代价=0+5*1+5*2+...+5*28=2030

33、若输入的n为15,接下来的输入是15到1,以及15到1,则输出为( C )。

A.2440

B.2220

C.2240

D.2420

【答案】:C

【解析】

第一次合并的代价是30,第二次合并的代价是58,第三次合并的代价是84,第四次合并的代价是108,第五次合并的代价是130,第六次合并的代价是150,第七次合并的代价是168,第八次合并的代价是184,第九次合并的代价是198,第十次合并的代价是210,第十一次合并的代价是220,第十二次合并的代价是228,第十三次合并的代价是234,第十四次合并的代价是238。

所有总的代价=30+58+84+108+...+238=2240,选C

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值