2017北京大学计算机学科夏令营上机考试

A:判决素数个数
查看提交统计提问
总时间限制: 1000ms 内存限制: 65536kB
描述
输入两个整数X和Y,输出两者之间的素数个数(包括X和Y)。

输入
两个整数X和Y(1 <= X,Y <= 105)。
输出
输出一个整数,表示X,Y之间的素数个数(包括X和Y)。
样例输入
1 100
样例输出
25

#include <stdio.h>
#include <math.h>
#include <string.h>
using namespace std;

const int MAXN=10010;

int vis[MAXN*2];
int tb,te,cnt=0;
int main()
{
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    int m=sqrt(MAXN+0.5);
    for(int i=2;i<=m;i++){
        if(!vis[i]){
            for(int j=i*i;j<=MAXN-2;j+=i){
                vis[j]=1;
            }
        }
    }
    scanf("%d %d",&tb,&te);
    if(tb>te){
        int tp=tb;
        tb=te;
        te=tp;
    }
    for(int i=tb;i<=te;i++){
        if(vis[i]==0){
            cnt++;
        }
    }
    printf("%d\n",cnt);
    return 0;
}

B:编码字符串(string)
查看提交统计提问
总时间限制: 1000ms 内存限制: 65536kB
描述
在数据压缩中,一个常用的方法是行程长度编码压缩。对于一个待压缩的字符串,我们可以依次记录每个字符及重复的次数。例如,待压缩的字符串为"aaabbbbcbb",压缩结果为(a,3)(b,4)(c,1)(b,2)。这种压缩对于相邻数据重复较多的情况有效,如果重复状况较少,则压缩的效率较低。

现要求根据输入的字符串,首先将字符串中所有大写字母转化为小写字母,然后将字符串进行压缩。

输入
一个字符串,长度大于0,且不超过1000,全部由大写或小写字母组成。
输出
输出为编码之后的字符串,形式为:(a,3)(b,4)(c,1)(d,2),即每对括号内分别为小写字符及重复的次数,不含任何空格。
样例输入
aAABBbBCCCaaaaa
样例输出
(a,3)(b,4)(c,3)(a,5)

#include <stdio.h>

int main()
{
    char tp,beg;
    int cnt;
    scanf("%c",&tp);
    beg=tp;
    cnt=1;

    while(1){
        scanf("%c",&tp);
        if(tp>='A'&&tp<='Z'){
            tp=tp+('a'-'A');
        }
        if(tp!=beg){
            printf("(%c,%d)",beg,cnt);
            beg=tp;
            cnt=1;
            if(tp=='\n'){
                break;
            }
        }else{
            cnt++;
        }
    }
    return 0;
}

C:岛屿周长(matrix)
查看提交统计提问
总时间限制: 1000ms 内存限制: 65536kB
描述
用一个nm的二维数组表示地图,1表示陆地,0代表海水,每一格都表示一个11的区域。地图中的格子只能横向或者纵向连接(不能对角连接),连接在一起的陆地称作岛屿,同时整个地图都被海水围绕。假设给出的地图中只会有一个岛屿,并且岛屿中不会有湖(即不会有水被陆地包围的情况出现)。请判断所给定的二维地图中岛屿的周长。

输入
第一行为n和m,表示地图的大小(1<=n<=100, 1<=m<=100)。接下来n行,每行有m个数,分别描述每一格的数值。数值之间均用空格隔开。
输出
只有一行,即岛屿的周长(正整数)。
样例输入
3 4
1 1 1 0
0 1 0 0
1 1 0 0
样例输出
14

#include <stdio.h>
#include <string.h>
const int MAXN=110;

int mapp[MAXN][MAXN];
int vis[MAXN][MAXN];
int dir[4][2]={0,1,
                1,0,
                0,-1,
                -1,0};
int n,m,cnt=0;

int dfs(int ni,int nj){
    if(vis[ni][nj]==1){
        return 0;
    }
    if(vis[ni][nj]==0&&mapp[ni][nj]==1){
        vis[ni][nj]=1;
    }
    if(mapp[ni][nj]==0){
        return 1;
    }
    for(int i=0;i<4;i++){
        int ti=ni+dir[i][0];
        int tj=nj+dir[i][1];
        cnt+=dfs(ti,tj);
    }
    return 0;
}

int main()
{
    memset(vis,0,sizeof(vis));
    memset(mapp,0,sizeof(mapp));
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&mapp[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            dfs(i,j);
        }
    }
    printf("%d",cnt);
    return 0;
}

D:Safecracker
查看提交统计提问
总时间限制: 1000ms 内存限制: 65536kB
描述
“The item is locked in a Klein safe behind a painting in the second-floor library. Klein safes are extremely rare; most of them, along with Klein and his factory, were destroyed in World War II. Fortunately old Brumbaugh from research knew Klein’s secrets and wrote them down before he died. A Klein safe has two distinguishing features: a combination lock that uses letters instead of numbers, and an engraved quotation on the door. A Klein quotation always contains between five and twelve distinct uppercase letters, usually at the beginning of sentences, and mentions one or more numbers. Five of the uppercase letters form the combination that opens the safe. By combining the digits from all the numbers in the appropriate way you get a numeric target. (The details of constructing the target number are classified.) To find the combination you must select five letters v, w, x, y, and z that satisfy the following equation, where each letter is replaced by its ordinal position in the alphabet (A=1, B=2, …, Z=26). The combination is then vwxyz. If there is more than one solution then the combination is the one that is lexicographically greatest, i.e., the one that would appear last in a dictionary.”

v - w2+ x3- y4+ z5= target

“For example, given target 1 and letter set ABCDEFGHIJKL, one possible solution is FIECB, since 6 - 92+ 53- 34+ 25= 1. There are actually several solutions in this case, and the combination turns out to be LKEBA. Klein thought it was safe to encode the combination within the engraving, because it could take months of effort to try all the possibilities even if you knew the secret. But of course computers didn’t exist then.”

"Develop a program to find Klein combinations in preparation for field deployment. Use standard test methodology as per departmental regulations.

输入
Input consists of one or more lines containing a positive integer target less than twelve million, a space, then at least five and at most twelve distinct uppercase letters. The last line will contain a target of zero and the letters END; this signals the end of the input.
输出
For each line output the unique Klein combination, or ‘no solution’ if there is no correct combination. Use the exact format shown below."
样例输入
1 ABCDEFGHIJKL
11700519 ZAYEXIWOVU
3072997 SOUGHT
1234567 THEQUICKFROG
0 END
样例输出
LKEBA
YOXUZ
GHOST
no solution

//pow()函数结果强制转化为int造成误差的分析,会直接截断
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;

int cmp(int a,int b){
    return a>b;
}

char arrstr[15];
int arrint[15];
int tar=1,tp;

int Print(int i,int j,int k,int l,int m){
    printf("%c",arrint[i]-1+'A');
    printf("%c",arrint[j]-1+'A');
    printf("%c",arrint[k]-1+'A');
    printf("%c",arrint[l]-1+'A');
    printf("%c\n",arrint[m]-1+'A');
    return 0;
}

int main(){
    scanf("%d %s",&tar,arrstr);
    while(tar!=0){
        int flag=0;
        memset(arrint,0,sizeof(arrint));
        int len=strlen(arrstr);
        for(int i=0;i<len;i++){
            arrint[i]=arrstr[i]-'A'+1;
        }
        sort(arrint,arrint+len,cmp);
        sort(arrstr,arrstr+len,cmp);
        for(int i=0;i<len&&flag==0;i++){
            for(int j=0;j<len&&flag==0;j++){
                if(i==j){
                    continue;
                }
                for(int k=0;k<len&&flag==0;k++){
                    if(k==i||k==j){
                        continue;
                    }
                    for(int l=0;l<len&&flag==0;l++){
                        if(l==k||l==j||l==i){
                            continue;
                        }
                        for(int m=0;m<len&&flag==0;m++){
                            if(m==l||m==k||m==j||m==i){
                                continue;
                            }
                            tp=arrint[i]-(int)pow(arrint[j],2);
                            tp+=(int)pow(arrint[k],3)-(int)pow(arrint[l],4);
                            tp+=(int)pow(arrint[m],5);
                            if(arrstr[i]=='Y'){
                                printf("%d %d %c %c %c %c %c\n",tar,tp,arrstr[i],arrstr[j],arrstr[k],arrstr[l],arrstr[m]);
                            }
                            if(tar==tp){
                                Print(i,j,k,l,m);
                                flag=1;
                            }
                        }
                    }
                }
            }
        }
        if(flag==0){
            printf("no solution\n");
        }
        scanf("%d %s",&tar,arrstr);
    }
    return 0;
}

E:怪盗基德的滑翔翼
查看提交统计提问
总时间限制: 1000ms 内存限制: 65536kB
描述
怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?

输入
输入数据第一行是一个整数K(K < 100),代表有K组测试数据。
每组测试数据包含两行:第一行是一个整数N(N < 100),代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h(0 < h < 10000),按照建筑的排列顺序给出。
输出
对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。
样例输入
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
样例输出
6
6
9

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int dp[110],arr[110];
int ans=0,n,t;

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&arr[i]);
        }
        memset(dp,0,sizeof(dp));
        dp[0]=1;//最长上升子序列
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(arr[j]<arr[i]){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
        }
        for(int i=0;i<n;i++){
            ans=max(ans,dp[i]);
        }

        memset(dp,0,sizeof(dp));
        dp[0]=1;//最长下降子序列
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(arr[j]>arr[i]){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
        }
        for(int i=0;i<n;i++){
            ans=max(ans,dp[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

G:实现堆结构
查看提交统计提问
总时间限制: 3000ms 内存限制: 65535kB
描述
定义一个数组,初始化为空。在数组上执行两种操作:

1、增添1个元素,把1个新的元素放入数组。

2、输出并删除数组中最小的数。

使用堆结构实现上述功能的高效算法。

输入
第一行输入一个整数t,代表测试数据的组数。
对于每组测试数据,第一行输入一个整数n,代表操作的次数。
每次操作首先输入一个整数type。
当type=1,增添操作,接着输入一个整数u,代表要插入的元素。
当type=2,输出删除操作,输出并删除数组中最小的元素。
1<=n<=100000。
输出
每次删除操作输出被删除的数字。
样例输入
2
5
1 1
1 2
1 3
2
2
4
1 5
1 1
1 7
2
样例输出
1
2
1
提示
每组测试数据的复杂度为O(nlgn)的算法才能通过本次,否则会返回TLE(超时)
需要使用最小堆结构来实现本题的算法

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int arr[100010],rong=0;
int t,n,to,tn;

int swapp(int a,int b){
    int tp=arr[a];
    arr[a]=arr[b];
    arr[b]=tp;
}

int del(){
    swapp(rong,1);
    rong--;
    int fa=1;
    while(fa*2+1<=rong){
        int minn=arr[fa*2]<arr[fa*2+1]?(fa*2):(fa*2+1);
        if(arr[minn]<arr[fa]){
            swapp(minn,fa);
        }else{
            break;
        }
        fa=minn;
    }
    if(fa*2<=rong&&arr[fa*2]<arr[fa]){
        swapp(fa*2,fa);
    }
    return arr[rong+1];
}

int add(int a){
    arr[++rong]=a;
    int zi=rong,fa=rong/2;
    while(zi!=1){
        if(arr[zi]>=arr[fa]){
            break;
        }else{
            swapp(fa,zi);
        }
        zi=zi/2;
        fa=fa/2;
    }
    return 0;
}

int main(){
    scanf("%d",&t);
    while(t--){
        rong=0;
        memset(arr,-1,sizeof(arr));
        scanf("%d",&n);
        while(n--){
            scanf("%d",&to);
            if(to==1){
                scanf("%d",&tn);
                add(tn);
            }else if(to==2){
                printf("%d\n",del());
            }
        }
    }
    return 0;
}

H:Subway
查看提交统计提问
总时间限制: 1000ms 内存限制: 65536kB
描述
You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of getting to ride your bike to school every day, you now get to walk and take the subway. Because you don’t want to be late for class, you want to know how long it will take you to get to school.
You walk at a speed of 10 km/h. The subway travels at 40 km/h. Assume that you are lucky, and whenever you arrive at a subway station, a train is there that you can board immediately. You may get on and off the subway any number of times, and you may switch between different subway lines if you wish. All subway lines go in both directions.
输入
Input consists of the x,y coordinates of your home and your school, followed by specifications of several subway lines. Each subway line consists of the non-negative integer x,y coordinates of each stop on the line, in order. You may assume the subway runs in a straight line between adjacent stops, and the coordinates represent an integral number of metres. Each line has at least two stops. The end of each subway line is followed by the dummy coordinate pair -1,-1. In total there are at most 200 subway stops in the city.
输出
Output is the number of minutes it will take you to get to school, rounded to the nearest minute, taking the fastest route.
样例输入

要复习最短路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值