2018年北京大学软件工程学科夏令营上机考试

2018年北京大学软件工程学科夏令营上机考试#

题目链接
密码:fighting
总体题目难度不大,都是常规题。就看谁写的快了。

A - 第K小最简真分数##

这个题不是这次考试的题目,A应该是签到,由于没有找到原题,找到一个"题目类似"作为补充。但是这个应该比其他任何题目都难。

题意:###

给一个整数N,请你求出以N为分母的最简(既约)真分数中第K小的是多少 。
$1 <= N <= 10000000000 且 1 <= K <= φ(N) $

题解:###

  • 唯一分解定律分解出的质数不超过20个。
  • 1到x有因子y的树的个数为$frac xy $个。
  • 容斥定理去重。
  • 对于任何一个分母N,包含其唯一分解定理分解出来的质因子,就一定不是真分数,使用容斥定理计算包含至少一个质因子的个数。求第K大,一般想到二分,二分答案即可。

代码:###

#include <iostream>
#include<stdio.h>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
ll a[2000],b[2000],tot;//a是因子乘积,b是代表奇偶。
ll K,N,l,r,Mid,ans;
ll prim[20],cnt;
void divide(ll n){
    ll y=n;
    for(ll i=2;i*i<=n;i++){
        if(y%i==0)prim[cnt++]=i;
        while(y%i==0&&y)y/=i;
    }
    if(y>1)prim[cnt++]=y;
}
void dfs(ll x,int y,int num){
    if(y==cnt){//遍历到最后一个因子
        if(x==1)return ;
        a[tot]=x;b[tot++]=(num&1)?1:-1;
        return;
    }
    dfs(x*prim[y],y+1,num+1);
    dfs(x,y+1,num);
}
bool check(ll n){
    ll num=0;//与n不互质的个数
    for(ll i=0;i<tot;i++){
        num+=n/a[i]*b[i];
    }
    return n-num>=K;
}
int main()
{
    cnt=0;
    tot=0;
    scanf("%lld%lld",&N,&K);
    divide(N);
    dfs(1,0,0);
    l=0;r=1e12;
    while(l<=r){
        Mid=(l+r)/2;
        if(check(Mid)){
            ans=Mid;
            r=Mid-1;
        }
        else l=Mid+1;
       //cout<<l<<"  "<<r<<endl;
    }
    printf("%lld
",ans);
    return 0;
}

B - n-gram串频统计##

题意:###

水题模拟

题解:###

暴力,使用map,可能写法比较麻烦

代码:###

#include <iostream>
#include <string>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include<map>
using namespace std;
map<string,int>map_cnt;
map<string,int>map_rk;
int main()
{
    int n;
    cin>>n;
    string str;
    cin>>str;
    for(int i=0;i<=str.size()-n;i++){
        string temp="";
        for(int j=0;j<n;j++){
            temp+=str[i+j];
        }
        map_cnt[temp]++;
    }
    map<string,int>::iterator it;
    int cnt=0;
    for(it=map_cnt.begin();it!=map_cnt.end();it++){
        cnt=max(cnt,(*it).second);
    }
    if(cnt<2){
        cout<<"NO"<<endl;
        return 0;
    }
    int ans=0;
    for(it=map_cnt.begin();it!=map_cnt.end();it++){
        if((*it).second==cnt)ans++;
    }
    cout<<cnt<<endl;
     for(int i=0;i<=str.size()-n;i++){
        string temp="";
        for(int j=0;j<n;j++){
            temp+=str[i+j];
        }
        if(map_cnt[temp]==cnt){
            if(!map_rk.count(temp)){
                cout<<temp<<endl;
            }
        map_rk[temp]++;
        }
    }

    return 0;
}

C - 垂直直方图##

题意:###

水题模拟

题解:###

暴力,读入一行可以使用gets,fgets,getline等函数。

代码:###

#include <iostream>
#include <string>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include<map>
using namespace std;
map<char,int>map_cnt;
int main()
{
    int max_cnt=0;
    for(int i=0;i<4;i++){
        string str;
        getline(cin,str);
        for(int i=0;i<str.size();i++){
            char ch=str[i];
            if(ch>='A'&&ch<='Z'){
                map_cnt[ch]++;
                max_cnt=max(max_cnt,map_cnt[ch]);
            }
        }
    }
    for(int i=max_cnt;i>0;i--){
        for(int j=0;j<26;j++){
            if(map_cnt['A'+j]==i){
                cout<<"* ";
                map_cnt['A'+j]--;
            }
            else cout<<"  ";
        }
        cout<<endl;
    }
    for(int i=0;i<26;i++){
        cout<<char('A'+i)<<" ";
    }
    cout<<endl;

D - Word-Search Wonder##

题意:###

在字符矩阵中,找到某个字符串在矩阵中的起点和终点。(保证最多一个解)

题解:###

暴力,八个方向探索。

代码:###

#include <iostream>
#include <string>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include<map>
using namespace std;
const int N=105;
char maze[N][N];
  int n;
void output(int x1,int y1,int x2,int y2){
    cout<<x1+1<<','<<y1+1<<" "<<x2+1<<","<<y2+1<<endl;
}
void gao(string str){
    int len=str.size();
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(maze[i][j]==str[0]){
                int n_i=i,n_j=j;
                //down
                while(n_i<n&&maze[n_i][j]==str[n_i-i])n_i++;
                if(n_i-i==len){
                    n_i--;
                    output(i,j,n_i,j);
                    return;
                }
                //up
                n_i=i,n_j=j;
                while(n_i>=0&&maze[n_i][j]==str[i-n_i])n_i--;
                if(i-n_i==len){
                    n_i++;
                    output(i,j,n_i,j);
                    return;
                }
                //r
                n_i=i,n_j=j;
                while(n_j<n&&maze[i][n_j]==str[n_j-j])
                    n_j++;
                if(n_j-j==len){
                    n_j--;
                    output(i,j,i,n_j);
                    return;
                }
                 //l
                 n_i=i,n_j=j;
                while(n_j>=0&&maze[i][n_j]==str[j-n_j])n_j--;
                if(j-n_j==len){
                    n_j++;
                    output(i,j,i,n_j);
                    return;
                }
                //x
                n_i=i,n_j=j;
                while(n_j<n&&n_i<n&&maze[n_i][n_j]==str[n_j-j])n_j++,n_i++;
                if(n_j-j==len){
                    n_j--;n_i--;
                    output(i,j,n_i,n_j);
                    return;
                }
                n_i=i,n_j=j;
                while(n_j>=0&&n_i>=0&&maze[n_i][n_j]==str[j-n_j])n_j--,n_i--;
                if(j-n_j==len){
                    n_i++;n_j++;
                    output(i,j,n_i,n_j);
                    return;
                }
                n_i=i,n_j=j;
                while(n_j>=0&&n_i<n&&maze[n_i][n_j]==str[j-n_j])
                    n_j--,n_i++;
                if(j-n_j==len){
                    n_j++;n_i--;
                    output(i,j,n_i,n_j);
                    return;
                }
                n_i=i,n_j=j;
                while(n_j<n&&n_i>=0&&maze[n_i][n_j]==str[n_j-j])n_j++,n_i--;
                if(n_j-j==len){
                    n_i++;n_j--;
                    output(i,j,n_i,n_j);
                    return;
                }

            }
        }
    }
    puts("Not found");
}

E - A Mini Locomotive##

题意:###

一共(n)车厢,每个车厢人数为(a_i),可以带走三段连续的车厢人数,求最多可以带走的人数。

题解:###

贪心不可取,DP,类似01背包问题。
(dp[i][j])表示遍历到第(i)个人,总共使用了(j)次的最大答案数量。

代码:###

#include <iostream>
#include <string>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include<map>
using namespace std;
const int N=5e4+10;
int a[N];
int pre[N];
int dp[N][4];
int n,len;
int main()
{
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        for(int i=0;i<n;i++)
            for(int j=0;j<3;j++)
                dp[i][j]=0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            if(i==0)pre[i]=a[i];
            else pre[i]=pre[i-1]+a[i];
        }
        cin>>len;

        for(int i=0;i<n;i++){
         for(int j=1;j<=3;j++){
               if(i<len)
                dp[i][j]=pre[i];
                else
               dp[i][j]=max(dp[i-1][j],dp[i-len][j-1]+pre[i]-pre[i-len]);
               //cout<<dp[i][j]<<"  ";
            }
           // cout<<endl;
        }
        cout<<dp[n-1][3]<<endl;

    }
    return 0;
}

EFG#

都不难,一个贪心;一个裸的最小生成树,这个题已经遇到了几次了;一个最小哈夫曼树的模拟。这三题都不写了。

I#

没找到题目来源。

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