zoukankan      html  css  js  c++  java
  • 【360】2019校招笔试编程题合集

    u1s1,好难。。两个小时根本做不完。最后找第三题的bug找到凌晨四点才过。


    试题链接:2019校招笔试编程题合集 

    1、城市修建

    题意:有一个城市需要修建,给你N个民居的坐标X,Y,问把这么多民居全都包进城市的话,城市所需最小面积是多少(注意,城市为平行于坐标轴的正方形)

    题解:记得看题,是正方形!!!。先开始一直没过以为是长方形来着。。

    记录输入的最大x,y和最小小x,y。然后相减,比较减出来最大的那个就是所求边长了。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int inf = 1e9*5;
     5 
     6 
     7 int main(){
     8     int n;
     9     cin>>n;
    10     ll x,y;
    11     ll x1 = inf,y1 = inf;
    12     ll x2 = -inf,y2 = -inf;
    13     for(int i = 0 ;i < n;i++){
    14         cin>>x>>y;
    15         x1 = min(x,x1);
    16         y1 = min(y,y1);
    17         x2 = max(x,x2);
    18         y2 = max(y,y2);
    19     }
    20 
    21     ll width = abs(x2-x1);
    22     ll height = abs(y2-y1);
    23 
    24     ll ans = max(width,height);
    25  
    26     cout<<ans*ans<<endl;
    27 
    28     return 0;
    29 }
    View Code

    2、圈地运动

    题意:圈地运动,就是用很多木棍摆在地上组成一个面积大于0的多边形~

    小明喜欢圈地运动,于是他需要去小红店里面买一些木棍,期望圈出一块地来。小红想挑战一下小明,所以给小明设置了一些障碍。障碍分别是:

    1.如果小明要买第i块木棍的话,他就必须把前i-1块木棍都买下来。

    2.买了的木棍都必须用在圈地运动中。

    那么请问小明最少买多少根木棍,才能使得木棍围成的图形是个面积大于0多边形呢?

    题解:这个本质是判断多边形的组成条件。构成m条边的多边形的条件,任意的m-1条边之和必须大于第m条边。

    我们根据这个性质来做判断,当前最大值的边是否小于其他边的和。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int inf = 1e9;
     5 
     6 int main(){
     7     int n;
     8     cin>>n;
     9     int cursum = 0;
    10     int maxlen = 0;
    11     int x;
    12     
    13     if(n < 3)   cout<<-1<<endl;
    14     else{
    15         int cnt = 1;
    16         int flag = 0;
    17         cin>>x;
    18         maxlen = x;
    19         for(int i = 1; i < n ;i++){
    20             cin>>x;
    21             cnt++;
    22             if(x > maxlen){
    23                 cursum += maxlen;
    24                 maxlen = x;
    25             }
    26             else    cursum += x;
    27 
    28             if(cursum > maxlen){
    29                 flag = 1;
    30                 break;
    31             }
    32             
    33         }
    34         if(flag)    cout<<cnt<<endl;
    35         else    cout<<-1<<endl;
    36 
    37     }
    38 
    39 
    40     return 0;
    41 }
    View Code

    3、Bittttttts

    题意:现在有q个询问,每次询问想问你在[l,r]区间内,k进制表示中,k-1的数量最多的数是哪个数。比如当k=2时,9的二进制就是1001,那么他就有2个1.

    题解:这题真的想了我好久。。本来准备用线段树做离线操作。后来发现1e16还是太大了。最后经韬韬点拨,发现可以这样思考。

    [l,r]这个区间我们不需要完全知道k进制以后的所有。

    • 首先需要比较l,r转化成k进制以后的数。补齐l的位数(因为l位数可能<=r的位数)
    • 然后从高位开始比较l,r每一位,如果当前位不相同,记录一下
    • 我们就从下一位开始将l的每一位变成k-1。(高位是根据l来判断的。因为所得数一定要在[l,r])
    • 考虑特殊情况(在下面讲解)
    • 转成十进制输出

    比如:  8进制下 1和100.   1->1   100->144

    首先补齐位数,001和144。从高位开始比较。可以得到最大的数是077。再转成十进制输出。

    不明白的话再举一个例子:10进制下, 987666666和987566666

    987666666

    987566666  那么我们转换的最大k-1的数是 987599999

    大概思路就是这样,里面的细节需要注意,下面就是特殊情况。

    1、当r全是k-1时,我们要输出r。比如10进制下11111 99999 ,此时应该输出99999

    2、当r从和l不等的这个pos这里全是k-1时,输出r。比如10进制下 1234567 1234999,此时输出1234999(这个情况想了好久,后面看到讨论区大佬给的数据才恍然大悟!!!!!)

    具体的看一下代码,代码里给了注释。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int inf = 1e9;
     5 
     6 ll maxnum = 0;
     7 ll ans = 0;
     8 
     9 vector<int> left_num;
    10 vector<int> right_num;
    11 
    12 //判断右边是不是全是k-1
    13 bool all_r(int k){
    14     int len = right_num.size();
    15     for(int i = 0 ;i < len;i++){
    16         if(right_num[i] != k-1){
    17             return false;
    18         }
    19     }
    20     return true;
    21 
    22 }
    23 
    24 ll query(int k,ll l, ll r){
    25     ll res = r; 
    26     while(l){
    27         left_num.push_back(l%k);
    28         l /= k;
    29     }
    30     while(r){
    31         right_num.push_back(r%k);
    32         r /= k;
    33     }
    34     //全为k-1的情况
    35     if(all_r(k)) return res;
    36 
    37     int len = right_num.size();
    38     int len1 = len - left_num.size();
    39 
    40     while(len1--)   left_num.push_back(0);
    41 
    42     ll ans=0;
    43     int pos = 0;
    44     for(int i = len-1 ; i >= 0 ;i--){
    45         if(left_num[i] != right_num[i]){
    46             pos = i;
    47             break;
    48         }   
    49     }
    50     //cout<<pos<<endl;
    51 
    52     int flag = 1;
    53     for(int i = pos ;i >= 0;i--){
    54         if(right_num[i] != k-1){
    55             flag = 0;
    56             break;
    57         }
    58     }
    59     if(flag)    return res;
    60     //[len-1,pos]按l
    61     for(int i = len-1; i >= pos ;i--)
    62         ans = ans*k + left_num[i];
    63     
    64     //[pos+1,0]按k-1
    65     for(int i = pos-1; i >= 0 ;i--)   
    66         ans = ans*k + k-1;
    67     
    68     return ans;
    69 }
    70 int main(){
    71     int q;
    72     cin>>q;
    73     int k;
    74     ll l,r;
    75     while(q--){
    76         cin>>k>>l>>r;
    77         left_num.clear();
    78         right_num.clear();
    79         cout<<query(k,l,r)<<endl;
    80     }
    81 
    82 
    83     return 0;
    84 }
    View Code

    4、看花

    题意:小明有一个花园,花园里面一共有m朵花,对于每一朵花,都是不一样的,小明用1~m中的一个整数表示每一朵花。

    他很喜欢去看这些花,有一天他看了n次,并将n次他看花的种类是什么按照时间顺序记录下来。

    记录用a[i]表示,表示第i次他看了a[i]这朵花。

    小红很好奇,她有Q个问题,问[l,r]的时间内,小明一共看了多少朵不同的花儿,小明因为在忙着欣赏他的花儿,所以想请你帮他回答这些问题。

    题解:查询区间内不同数的个数。标准主席树。。

    我就直接上板子了。这里记得用c的输入输出否则TLE。讨论区好像set暴力可行。。

    代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define ll long long
      4 const int maxn = 30010;
      5 const int M = maxn*100;
      6 
      7 int a[maxn];
      8 int T[maxn],lson[M],rson[M];
      9 int c[M];   //保存当前根节点中元素的个数
     10 
     11 int n,m,q,tot;
     12 
     13 //建树
     14 int build(int l,int r){
     15     int root = tot++;
     16     c[root] = 0;
     17     if(l!=r){
     18         int mid = (l+r)>>1;
     19         lson[root] = build(l,mid);
     20         rson[root] = build(mid+1,r);
     21     }
     22     return root;
     23 }
     24 
     25 int update(int root,int pos,int val){
     26     int newroot = tot++;
     27     int tmp = newroot;
     28     c[newroot] = c[root] + val;
     29     int l = 1,r = n;
     30     while(l < r){
     31         int mid = (l+r)>>1;
     32         if(pos <= mid){
     33             lson[newroot] = tot++;
     34             rson[newroot] = rson[root];
     35             newroot = lson[newroot];    
     36             root = lson[root];
     37             r = mid;
     38         }
     39         else{
     40             rson[newroot] = tot++;
     41             lson[newroot] = lson[root];
     42             newroot = rson[newroot];
     43             root = rson[root];
     44             l = mid+1;
     45         }
     46         c[newroot] = c[root]+val;
     47     }
     48     return tmp;
     49 }
     50 
     51 int query(int root,int pos){
     52     int ret = 0;
     53     int l = 1,r = n;
     54     while(pos < r){
     55         int mid = (l+r)>>1;
     56         if(pos <= mid){
     57             r = mid;
     58             root = lson[root];
     59         }
     60         else{
     61             ret += c[lson[root]];
     62             root = rson[root];
     63             l = mid+1;
     64         }
     65     }
     66     return ret + c[root];
     67 }
     68 
     69 
     70 int main(){
     71     scanf("%d%d",&n,&m);
     72     //cin>>n>>m;
     73     tot = 0;
     74     for(int i = 1;i <= n ;i++){
     75         scanf("%d",&a[i]);
     76         //cin>>a[i];
     77     }
     78     T[n+1] = build(1,n);
     79     map<int,int>mp;
     80     for(int i = n ;i >= 1;i--){
     81         if(mp.find(a[i]) == mp.end()){
     82             T[i] = update(T[i+1],i,1);
     83         }
     84         else{
     85             int tmp = update(T[i+1],mp[a[i]],-1);
     86             T[i] = update(tmp,i,1);
     87         }
     88         mp[a[i]] = i;
     89     }
     90     scanf("%d",&q);
     91     //cin>>q;
     92     while(q--){
     93         int l,r;
     94         scanf("%d%d",&l,&r);
     95         //cin>>l>>r;
     96         printf("%d
    ",query(T[l],r));
     97         //cout<<query(T[l],r)<<endl;
     98     }
     99     
    100     return 0;
    101 }
    View Code

    5、Array

    题意:小红有两个长度为n的排列A和B。每个排列由[1,n]数组成,且里面的数字都是不同的。

    现在要找到一个新的序列C,要求这个新序列中任意两个位置(i,j)满足:

    如果在A数组中C[i]这个数在C[j]的后面,那么在B数组中需要C[i]这个数在C[j]的前面。

    请问C序列的长度最长为多少呢?

    题解:这个题最开始想到是逆序B数组,找AB的LCS。二维DP,明显TLE(30%)

    然后优化成一维DP,还是不行(40%)交完卷以后康康别人的讨论得到灵感。

    我们用一个map来标记A数组中数字的索引。在B数组的输入时直接给当前数字的索引。

    转化成寻找最长下降子序列(感叹一下这个操作真的很巧妙。。)

    举例:A:12435   B:52341

    A:  1 2 4 3 5

    mp:  0 1 2 3 4

    B:    4 1 3 2 0

    此时就是找B中最长下降子序列:4 3 2 0得到长度是4。

    这里要用O(nlogn)优化过时间的算法。可以自己写二分,也可以用STL自带。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn = 1e5+10;
     5 const int inf = 0xfffffff;
     6 int n;
     7 int b[maxn];
     8 int dp[maxn]= {0};
     9  
    10 /*
    11 int search(int x){
    12     int l,r,mid;
    13     l = 0;r = n;
    14     while(l < r){
    15         mid = (l+r)/2;
    16         if(b[mid] >= x)  r = mid;
    17         else    l = mid+1;
    18     }
    19  
    20     return l;
    21 }*/
    22  
    23  
    24 int main(){
    25      
    26     cin>>n;
    27     int x;
    28  
    29     map<int,int>mp;
    30  
    31     for(int i = 0; i < n; i++){
    32         cin>>x;
    33         mp[x] = i;
    34     }
    35     for(int i = 0; i < n ;i++){
    36         cin>>x;
    37         b[i] = mp[x];
    38     }
    39     /*
    40     for(int i = 0; i < n ;i++){
    41         cout<<b[i]<<" ";
    42     }
    43     cout<<endl;*/
    44  
    45     memset(dp,0,sizeof(dp));
    46  
    47     int ans = 0;
    48     dp[0] = b[0];
    49  
    50     for(int i = 1 ; i < n ;i++){
    51         if(b[i] < dp[ans])
    52             dp[++ans] = b[i];
    53         else
    54             //dp[search(b[i])] = b[i];
    55             dp[lower_bound(dp, dp+n, b[i], greater <int> ()) - dp] = b[i];
    56     } 
    57  
    58  
    59     cout<<ans+1<<endl;
    60  
    61  
    62     return 0;
    63 }
    View Code

    6、魔法排列

    题意:众所周知,集合{1 2 3 … N}有N!种不同的排列,假设第i个排列为Pi且Pi,j是该排列的第j个数。将N个点放置在x轴上,第i个点的坐标为xi且所有点的坐标两两不同。对于每个排列(以Pi为例),可以将其视为对上述N个点的一种遍历顺序,即从第Pi,1个点出发,沿直线距离到达第Pi,2个点,再沿直线距离到达第Pi,3个点,以此类推,最后到达第Pi,N个点,将该路线的总长度定义为L(Pi),那么所有N!种路线的总长度之和是多少,即L(P1)+L(P2)+L(P3)+...+L(PN!)的结果是多少?

    题解:用STL里next_permutation能过26.67%。当时时间已经不够了。。。

    讨论区大佬的题解写的很详细。。但是我还是有点不太会推。。等我下午推了我补一下过程。

    先给公式。。

    $num_k = [k*(N-k) + k*(N-k)]*(N-1)! = 2*k*(N-k)*(N-1)!$

    $D_{total} = sum ^{N-1}_{k = 1} num_k * d_k$

    取模一定要记得每一步最好都要取模,不能一下子一起取,会出现溢出的情况。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn = 1e5+10;
     5 const int mod = 1e9+7;
     6 
     7 int num[maxn];
     8 ll ans = 0;
     9 int n;
    10 
    11 int main(){
    12     cin>>n;
    13     for(int i = 0; i < n ;i++){
    14         cin>>num[i];
    15     }
    16     ll fac = 1; //n-1的阶乘
    17     for(int i = 1;i < n ;i++)
    18         fac = (fac*i + mod)%mod;
    19 
    20     ll dis = 0; //表示d
    21     ll a;
    22 
    23     for(ll i = 1; i < n ;i++){
    24         dis = (num[i]-num[i-1]) % mod;
    25         a = 2*i*(n-i)%mod;
    26         a = (a*dis)%mod;
    27         ans = (ans+a)%mod;
    28     }
    29 
    30     ans = (ans * fac) % mod;
    31 
    32     cout<<ans<<endl;
    33     return 0;
    34 }
    View Code
  • 相关阅读:
    Leetcode题目62.不同路径(动态规划-中等)
    Leetcode题目56.合并区间(中等)
    Leetcode题目55.跳跃游戏(贪心算法-中等)
    Leetcode题目53.最大子序和(动态规划-简单)
    Leetcode题目49.字母异位词分组(中等)
    Leetcode题目48.旋转图像(中等)
    Leetcode题目46.全排列(回溯+深度优先遍历+状态重置-中等)
    Leetcode题目39.组合总和(回溯+剪枝-中等)
    Android学习笔记-Universal-Image-Loade图片加载框架
    Android学习笔记--使用Apache HttpClient实现网络下载效果,附带进度条显示
  • 原文地址:https://www.cnblogs.com/Asumi/p/12551707.html
Copyright © 2011-2022 走看看