2018北大计算机学科夏令营机试题目

2018北大计算机学科夏令营机试题目#

题目链接
密码依然是fighting!

百练上北大夏令营的机试题目,全部拉到Virtual judge了 ,给我的感觉是2019的夏令营题目比2018难了一大截。不知道是偶然还是趋势。

A - 计算两个日期之间的天数

题目大意:计算两个日期差
题解:模拟水题,我用的是日期相减。没有写函数,导致中间一个变量用错了,Wa 2,绝了。以后还是多封装函数,不要写复制重复代码,就不贴代码了。

B - 回文子串

题目大意:
暴力找回文串
题解:
O(n^3)暴力即可

#include <iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<cmath>
using namespace std;
string str;
bool is_ok(int i,int j){
    while(str[i]==str[j]){
        i++;
        j--;
        if(j<=i)return 1;
    }
    return 0;
}
int main()
{
    cin>>str;
    int n=str.length();
    for(int i=2;i<=n;i++){
        for(int j=0;j<n;j++){
                int ed=i+j-1;
            if(ed<n){
                if(is_ok(j,ed)){
                    for(int k=j;k<=ed;k++){
                        cout<<str[k];
                    }
                    cout<<endl;
                }
            }
        }
    }
    return 0;
}

C - The Die Is Cast

题目大意:
双层联通块
题解:
不知道网上题解怎么写的。我是找到第一层联通快,然后找第二层联通快。写了两个DFS,代码冗长。

#include <iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<vector>
#include<cmath>
using namespace std;
char maze[55][55];
char temp[55][55];
char a[55][55];
bool vis[55][55];
bool vis2[55][55];
bool cur[55][55];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int w,h;
bool in(int x,int y){
    if(x>=0&&x<h&&y>=0&&y<w)return 1;
    return 0;
}
void dfs2(int i,int j){
     vis2[i][j]=1;
     for(int ii=0;ii<4;ii++){
        int x=i+dx[ii];
        int y=j+dy[ii];
        if(in(x,y)&&!vis2[x][y]&&temp[x][y]=='X'){
           dfs2(x,y);
        }
    }
}
vector<int>ve;
void gao(){
    memset(vis2,0,sizeof vis2);
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            temp[i][j]=maze[i][j];
            if(temp[i][j]=='X'&&cur[i][j]==0)
                temp[i][j]='.';
        }
    }
    int cnt=0;
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            if(temp[i][j]=='X'&&!vis2[i][j]){
                dfs2(i,j);
                cnt++;
            }
        }
    }
    ve.push_back(cnt);

}
void dfs(int i,int j){
    vis[i][j]=1;
    cur[i][j]=1;
    for(int ii=0;ii<4;ii++){
        int x=i+dx[ii];
        int y=j+dy[ii];
        if(in(x,y)&&!vis[x][y]&&(maze[x][y]=='X'||maze[x][y]=='*')){
            dfs(x,y);
        }
    }
}
int main()
{
    int   T=0;
    while(cin>>w>>h&&w!=0){
        cout<<"Throw "<<++T<<endl;
        ve.clear();
        memset(vis,0,sizeof(vis));
        for(int i=0;i<h;i++)
            for(int j=0;j<w;j++)
            cin>>maze[i][j];
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                if(maze[i][j]=='*'||maze[i][j]=='X'){
                    if(!vis[i][j]){
                        memset(cur,0,sizeof cur);
                        dfs(i,j);
                        gao();
                    }
                }

            }
        }
        sort(ve.begin(),ve.end());
        for(int i=0;i<ve.size();i++){
            cout<<ve[i]<<" ";
        }
        cout<<endl<<endl;

    }
    return 0;
}

D - 食物链##

题目大意:
白书原题,很多人应该都写过
题解:
个人感觉采用一般并查集不是很好理解,下面采用带权并查集。带圈并查集才写了一个题,理解的肯定是不深刻。带权含义是每个节点到根节点的连线上存在一个权值,权值表示一定含义,节点合并时,需要加入权值信息,在路径压缩中,要保持每个节点到根节点权值不变,故需要做一些修改工作。本例中的三个种群分别代码节点到根节点的权值为0,1,2。
这个题神奇之处是,必须要scanf,cin会TLE。

#include <iostream>
#include<cstring>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=5e4+10;
int n,k;
int pre[N],val[N];
void init(){
    for(int i=0;i<=n;i++)pre[i]=i,val[i]=0;
}
int find(int x){
    int px=pre[x];
    if(x!=pre[x]){
        pre[x]=find(pre[x]);
        val[x]=(val[x]+val[px])%3;
    }
    return pre[x];
}
int main()
{
    scanf("%d%d",&n,&k);
    int cnt=0;
    init();
    while(k--){
        int d,x,y;
        scanf("%d%d%d",&d,&x,&y);
        int fx=find(x);
        int fy=find(y);
        if(x>n||y>n||(x==y&&d==2))cnt++;
        else if(fx==fy&&(val[x]-val[y]+3)%3!=(d-1))cnt++;
        else if(fx!=fy){
            pre[fx]=fy;
            val[fx]=(val[y]-val[x]+3+(d-1))%3;
        }
    }
    cout<<cnt<<endl;
    return 0;
}

E - 反正切函数的应用##

题目大意:
二元(b,c)一次解方程,求满足条件的最小b+c的值。
题解:
有点像高中数学题,但是我没有想到解法。参考网上的,就是变量代换,代换两轮,变成对勾函数的形式,在转折点取到最小值,由于要求整数,所以要枚举。不知道什么只需要枚举左边就好了。

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

int main()
{
    long long a;
    cin>>a;
    for(int i=a;i>0;i--){
        if((a*a+1)%i==0){
            cout<<(i+(a*a+1)/i+2*a)<<endl;
            break;
        }
    }
    return 0;
}

F - Euro Efficiency##

题目大意:
给定六种硬币面值[1,100),求拼出[1,100]的每个数,最少需要参与的硬币个数为多少。(各种硬币个数不限,可以找钱(也就是做减法))。
题解:
完全背包,背包问题必须要很熟悉,经常出现。我这里做法有点不一样,只做了一次完全背包,之后枚举给钱的总钱数,取一个min。
这个N值要稍大,给的钱数理论最大值为100*100。
输出用%.lf wa了,也是很神奇,网上说和%.f没有区别,以后还是%.f为妙。

#include <iostream>
#include<stdio.h>
using namespace std;
int price[6];
const int N=20000+10;
int dp[6][N];
int main()
{
    int T;
    cin>>T;
    while(T--){
        for(int i=0;i<6;i++){
            cin>>price[i];
        }
        for(int i=0;i<6;i++){
            for(int j=1;j<N;j++){
                if(i==0)dp[i][j]=j;
                else{
                    for(int k=0;k<=i;k++){
                    if(j<price[k])break;
                    if(k==0)
                        dp[i][j]=dp[k][j-price[k]]+1;

                    else dp[i][j]=min(dp[i][j],dp[k][j-price[k]]+1);
                    }
                }
            }
        }
        int all=0;
        int maxx=0;
        int cur;
        for(int i=1;i<=100;i++){
            cur=1000;
            for(int j=N-1;j>=i;j--){
                cur=min(cur,dp[5][j]+dp[5][j-i]);
            }
            maxx=max(cur,maxx);
            all+=cur;
        }

        printf("%.2f %d
",all/100.0,maxx);
    }
    return 0;
}

G - Tram##

题目大意:
简单最短路
题解:
建图十分简单,边上的权值0或者1或者INF,再使用任意最短路算法,Floyd最简单,注意Floyd首先枚举中间点。

#include <iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=105;
const int INF=0x3f3f3f;
int n,a,b;
int dis[N][N];
int main()
{
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            dis[i][j]=INF;
          //  if(i==j)dis[i][j]=0;
        }
    }
    for(int i=1;i<=n;i++){
        int k,e;
        cin>>k;
        for(int j=0;j<k;j++){
            cin>>e;
            if(j==0)dis[i][e]=0;
            else dis[i][e]=1;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++){
                dis[j][k]=min(dis[j][k],dis[j][i]+dis[i][k]);
            }
    if(dis[a][b]>=INF)cout<<-1<<endl;
    else cout<<dis[a][b]<<endl;
    return 0;
}

H就不做了,逃。。。。。

原文地址:https://www.cnblogs.com/gzr2018/p/12372505.html