网易2017校招编程题

内推挂了,继续再战!

1、分苹果:

小易去买苹果,有两种包装,一种一袋8个,一种一袋6个,小易要买n个苹果(不能多也不能少),输出袋子最少的购买方案下的袋子,若无法正好买到n个,则输出-1。

 

解:设8个一袋的买了pack8袋,6个一袋的买了pack6袋。想要总袋子数最少,那么肯定优先买8个一袋的,最多能买n/8袋,先另pack8=n/8,计算该情况下,pack6为多少能满足总苹果数为6,若无法满足,则减少pack8的数量,直到可以满足总量为n。

 

#include<iostream>
using namespace std;
int main() {
    int n;
    cin>>n;
    int pack8=n/8;
    int pack6=0;
    for(pack8;pack8>=0;pack8--)
    {
        if((n-8*pack8)%6==0)
        {
            cout<<pack8+(n-8*pack8)/6<<endl;
            return 0;
        }
    }
    cout<<-1<<endl;
    return 0;
}

 

2、大数的最大奇约数

    用f(n)表示n的最大奇约数,输入一个数n,输出f(1)+f(2)+f(3)+...+f(n)。1<=n<=1000000000

 

解:说一下我的思路以及经过的一些曲折。当然第一个想到的方法就是暴力破解,用一个函数f(n),将n循环除2直到为奇数则返回,但是很明显,本题中n的取值范围很大,这样会超时。

     然后想着找规律,首先奇数的最大奇约数就是自己,可以暂时不考虑,最后用等差数列求和公式加进来就可以。对于偶数n来说,每个数都可以表示成2^k*i,其中i为奇数,则i就是它的最大奇约数,我们要做的就是把所有的i加进来。首先,我想到的是存储一下每个偶数ni对应的i,之后只要遍历n,找到对应的i加起来就可以了。既然用偶数n来作为遍历的基准会超时,那考虑从k和i出发。选用了map的数据结构,觉得可以方便查找,然后双层循环,第一层是k,第二层是i,边界条件为2^k*i<=n,将n作为key,i作为value存进map。然后又出现了新问题,map太大,超出内存限制。

     然后想到了,为什么要存起来呢,直接加进结果就可以了。设置一个count,来统计已经计算过的偶数数量,作为循环的终止条件。该方法的时间复杂度为O(n/2)。PS:开始只将结果定义为了Long型,发现测试用例只能通过一部分,后来想到中间结果也可能会溢出,都应该定义为long型。

#include <iostream>
using namespace std;

int main()
{
    long n;
    cin>>n;
    long long res=0;
    long t=2;//用t表示2^k
    int count=0;
    while(count<n/2)
    {
        for(long i=1;t*i<=n;i=i+2)//找到2^k*i<=n的所有i
        {
            res=res+i;
            count++;  
        }
        t=t*2;
    }
    if(n%2==0) //当n为奇数时,序列中的奇数和
    {
        res=res+n*n/4;            
    }
    else//当n为偶数时,序列中的奇数和
    {
        res=res+(n+1)*(n+1)/4;        
    }
    cout<<res<<endl;
    return 0;
}

 

3、 优雅的点

小易有一个圆心在坐标原点的圆,小易知道圆的半径的平方。小易认为在圆上的点而且横纵坐标都是整数的点是优雅的,小易现在想寻找一个算法计算出优雅的点的个数,请你来帮帮他。
例如:半径的平方如果为25
优雅的点就有:(+/-3, +/-4), (+/-4, +/-3), (0, +/-5) (+/-5, 0),一共12个点。

 
  解:对于每一个正整数的x坐标值,计算可能对应的在圆上的点的正整数y坐标值。若该点在坐标轴上,与其对称的还有一个符合要求的点;若不在坐标轴上,则有3个与其对称的点(各象限都有一个)。
#include <iostream>
#include <math.h>
using namespace std;
#define MAXINT 99999



int main()
{
    double n;
    cin>>n;
    int res=0;
    int r=sqrt((double)n);
    for(int i=0;i<=sqrt(n)+1;i++)
    {
        int j=sqrt(n-i*i);
        if(i*i+j*j==n)
        {
            if(i==0||j==0)
                res=res+2;
            else
                res=res+4;
        }
    }
    cout<<res<<endl;
    return 0;
}

 

4、暗黑的字符串

    一个只包含'A'、'B'和'C'的字符串,如果存在某一段长度为3的连续子串中恰好'A'、'B'和'C'各有一个,那么这个字符串就是纯净的,否则这个字符串就是暗黑的。例如:
     BAACAACCBAAA 连续子串"CBA"中包含了'A','B','C'各一个,所以是纯净的字符串
      AABBCCAABB 不存在一个长度为3的连续子串包含'A','B','C',所以是暗黑的字符串
     你的任务就是计算出长度为n的字符串(只包含'A'、'B'和'C'),有多少个是暗黑的字符串。 (1 ≤ n ≤ 30)

    解:首先想到递归,若确定了字符串前start-1的排列方式,判断从start起接下来有多少种排列方式。但是该方法时间复杂度过大。于是想到动态规划。

         暗黑字符串中,第i位可以为'A','B','C'中的哪些值,取决于i的前两位的排列方式,所有用dp[i][subseq],记录到第i位为止,第i-1、i位的排列为subseq(subseq可以有9中排列)的暗黑字符串的个数,例如,dp[i][AA]表示第i-1位为A且第i位也为A的暗黑字符串的个数。遍历i,依次求出dp[i][]的值,则dp[n-1]维中9个数相加的和则为所求。

#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
#define MAXINT 9999999
#define AA 0
#define AB 1
#define AC 2
#define BA 3
#define BB 4
#define BC 5
#define CA 6
#define CB 7
#define CC 8
#define ll long long
int main()
{
    int n;
    while(cin>>n)
    {
        
        if(n==1)
        {
            cout<<3<<endl;
            continue;
        }
        if(n==2)
        {
            cout<<9<<endl;
            continue;
        }
        
        ll dp[30][9];
        for(int i=0;i<9;i++)
            dp[1][i]=1;
        for(int i=2;i<n;i++)
        {
            dp[i][AA]=dp[i-1][AA]+dp[i-1][BA]+dp[i-1][CA];
            dp[i][AB]=dp[i-1][AA]+dp[i-1][BA];
            dp[i][AC]=dp[i-1][AA]+dp[i-1][CA];
            dp[i][BA]=dp[i-1][AB]+dp[i-1][BB];
            dp[i][BC]=dp[i-1][BB]+dp[i-1][CB];
            dp[i][BB]=dp[i-1][AB]+dp[i-1][BB]+dp[i-1][CB];
            dp[i][CA]=dp[i-1][AC]+dp[i-1][CC];
            dp[i][CB]=dp[i-1][BC]+dp[i-1][CC];
            dp[i][CC]=dp[i-1][AC]+dp[i-1][BC]+dp[i-1][CC];
        }
        ll res=0;
        for(int i=0;i<9;i++)
            res=res+dp[n-1][i];
        cout<<res<<endl;
    }
    return 0;
}

5、 数字翻转

       对于一个整数X,定义操作rev(X)为将X按数位翻转过来,并且去除掉前导0。例如:
     如果 X = 123,则rev(X) = 321;
     如果 X = 100,则rev(X) = 1.
     现在给出整数x和y,要求rev(rev(x) + rev(y))为多少?

#include <iostream>
#include <list>
using namespace std;
int rev(int x)
{
    list<int> tmp;
    while(x)
    {
        tmp.push_back(x%10);
        x=x/10;
    }
    int res=0;
    while(tmp.front()==0)
    {
        tmp.pop_front();
    }
    while(!tmp.empty())
    {
        res=res*10+tmp.front();
        tmp.pop_front();
    }
    return res;
}
int main()
{
    int x,y;
    cin>>x>>y;
    x=rev(x);
    y=rev(y);
    cout<<rev(x+y)<<endl;
    return 0;
}

6、计算糖果

A,B,C三个人是好朋友,每个人手里都有一些糖果,我们不知道他们每个人手上具体有多少个糖果,但是我们知道以下的信息:
A - B, B - C, A + B, B + C. 这四个数值.每个字母代表每个人所拥有的糖果数.
现在需要通过这四个数值计算出每个人手里有多少个糖果,即A,B,C。这里保证最多只有一组整数A,B,C满足所有题设条件。

输入描述:

输入为一行,一共4个整数,分别为A - B,B - C,A + B,B + C,用空格隔开。
范围均在-30到30之间(闭区间)。
输出描述:
输出为一行,如果存在满足的整数A,B,C则按顺序输出A,B,C,用空格隔开,行末无空格。
如果不存在这样的整数A,B,C,则输出No

 解:首先A,B,C的值肯定都大于等于0,且为整数。由于A+B的范围在[0,30],所以直接遍历的时间复杂度并不高。以A为基准进行遍历,当A=a时,则b=(A+B)-a,再判断是否满足a-b=A-B,不满足则改变a的值,继续遍历;若满足,则c=(B+C)-b,判断是否满足b-c=B-C,不满足则改变a的值,继续遍历;满足则跳出,已经确定了A,B,C的值。

#include <iostream>
using namespace std;

int main()
{
    int AMB,BMC,APB,BPC;
    cin>>AMB>>BMC>>APB>>BPC;
    int a=0,b=0,c=0;
    bool exi=false;//记录是否存在这样的A,B,C
    for(a=0;a<=APB;a++)
    {
        b=APB-a;
        if(a-b!=AMB)
            continue;
        c=BPC-b;
        if(b-c!=BMC)
            continue;
        exi=true;
        break;
    }
    if(exi)
        cout<<a<<" "<<b<<" "<<c<<endl;
    else
        cout<<"No"<<endl;
    return 0;
}

 

posted @ 2016-09-14 10:25  翎飞蝶舞  阅读(1349)  评论(0编辑  收藏  举报