微软笔试题

题目1 : Farthest Point

时间限制: 5000ms
单点时限: 1000ms
内存限制: 256MB

描述

Given a circle on a two-dimentional plane.

Output the integral point in or on the boundary of the circle which has the largest distance from the center.

输入

One line with three floats which are all accurate to three decimal places, indicating the coordinates of the center x, y and the radius r.

For 80% of the data: |x|,|y|<=1000, 1<=r<=1000

For 100% of the data: |x|,|y|<=100000, 1<=r<=100000

输出

One line with two integers separated by one space, indicating the answer.

If there are multiple answers, print the one with the largest x-coordinate.

If there are still multiple answers, print the one with the largest y-coordinate.


样例输入
1.000 1.000 5.000
样例输出
6 1

这道题的思路,我一开始是用圆上的点坐标公式x=x0+r*cos(θ),y=y0+r*sin(θ)。然后枚举角度θ(步长为0.001,范围为>=0&&<=360),这样做法的缺点1.是不容易控制步长,当r非常大的时候,步长可能需要很小。2.因为步长比较小,所以复杂度比较高。3.由于θ从0到360进行枚举,所以无法保证在距离优先的前提之下,x优先以及y优先。后来看了别人的代码发现一个更好的思路,那边是:枚举x!!!代码如下:

#include <iostream>
#include <cmath>
using namespace std;
//算法思想是由右至左,枚举x。枚举x的同时,枚举圆心上下两侧的y,先上面,后下面。
int main()
{
    double x,y,r;
    while(cin>>x>>y>>r)
    {
        int right=(int)floor(x+r); //x最大整数值
        int left=(int)ceil(x-r); //x最小整数值
        int a=0,b=0;
        double dis=0;
        for(int i=right;i>=left;--i) //枚举x
        {
            double j=y+sqrt(r*r-(i-x)*(i-x)); //枚举y
            double jf=floor(j);
            double diss=sqrt((i-x)*(i-x)+(jf-y)*(jf-y));
            if(diss>dis)
                a=i,b=(int)jf,dis=diss;
            j=y-sqrt(r*r-(i-x)*(i-x)); //y可能在圆心的另外一侧
            jf=ceil(j);
            diss=sqrt((i-x)*(i-x)+(jf-y)*(jf-y));
            if(diss>dis)
                a=i,b=(int)jf,dis=diss;
        }
        cout << a << " " << b << endl;
    }
}

题目2 : Total Highway Distance

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

Little Hi and Little Ho are playing a construction simulation game. They build N cities (numbered from 1 to N) in the game and connect them by N-1 highways. It is guaranteed that each pair of cities are connected by the highways directly or indirectly.

The game has a very important value called Total Highway Distance (THD) which is the total distances of all pairs of cities. Suppose there are 3 cities and 2 highways. The highway between City 1 and City 2 is 200 miles and the highway between City 2 and City 3 is 300 miles. So the THD is 1000(200 + 500 + 300) miles because the distances between City 1 and City 2, City 1 and City 3, City 2 and City 3 are 200 miles, 500 miles and 300 miles respectively.

During the game Little Hi and Little Ho may change the length of some highways. They want to know the latest THD. Can you help them?

输入

Line 1: two integers N and M.

Line 2 .. N: three integers u, v, k indicating there is a highway of k miles between city u and city v.

Line N+1 .. N+M: each line describes an operation, either changing the length of a highway or querying the current THD. It is in one of the following format.

EDIT i j k, indicating change the length of the highway between city i and city j to k miles.

QUERY, for querying the THD.

For 30% of the data: 2<=N<=100, 1<=M<=20

For 60% of the data: 2<=N<=2000, 1<=M<=20

For 100% of the data: 2<=N<=100,000, 1<=M<=50,000, 1 <= u, v <= N, 0 <= k <= 1000.

输出

For each QUERY operation output one line containing the corresponding THD.

样例输入
3 5
1 2 2
2 3 3
QUERY
EDIT 1 2 4
QUERY
EDIT 2 3 2
QUERY
样例输出
10
14
12

题目比较简单,有两个关键的技巧点。1.使用嵌套的hash map,用于保存一条边的长度。2.当改变某一条边长度的时候,thd += (n-1)*(len-ori)。n-1为边的数目,len为新的长度,ori为这条边原来的长度。代码如下:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;
int main() {
    int n, m;
    cin >> n >> m;
    unordered_map<int, unordered_map<int, int>> point_dis;
    int a, b, dis;
    long long thd = 0;
    for (int i=1; i<n; i++) {
        cin >> a >> b >> dis;
        point_dis[a][b] = dis;
        point_dis[b][a] = dis;
        thd += (n-1)*dis;
    }
    string line;
    int len;
    for (int i=0; i<m; i++) {
        cin >> line;
        if (line=="QUERY") {
            cout << thd << endl;
        } else if(line=="EDIT"){
            cin >> a >> b >> len;
            int ori = point_dis[a][b];
            thd += (n-1)*(len-ori);
            point_dis[a][b] = point_dis[b][a] = len;
            
        }
    }
}



题目3 : Fibonacci

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

Given a sequence {an}, how many non-empty sub-sequence of it is a prefix of fibonacci sequence.

A sub-sequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements.

The fibonacci sequence is defined as below:

F1 = 1, F2 = 1

Fn = Fn-1 + Fn-2, n>=3

输入

One line with an integer n.

Second line with n integers, indicating the sequence {an}.

For 30% of the data, n<=10.

For 60% of the data, n<=1000.

For 100% of the data, n<=1000000, 0<=ai<=100000.

输出

One line with an integer, indicating the answer modulo 1,000,000,007.

样例提示

The 7 sub-sequences are:

{a2}

{a3}

{a2, a3}

{a2, a3, a4}

{a2, a3, a5}

{a2, a3, a4, a6}

{a2, a3, a5, a6}


样例输入
6
2 1 1 2 2 3
样例输出
7
这道题目的思路,我一开始用的是DFS+回溯,时间复杂度会比较高。后来看了中山大学一个哥们的代码,发现用DP更为简便,时间复杂度也可以降为O(n)。DP思想为:设count[i]为以第i个斐波那契数结尾的斐波那契数列的个数,当遇到第i+1个斐波那契数的时候,可知count[i+1]+=count[i]。为什么?因为这个数(也就是第i+1个fibo数),可以和之前的任意一个以第i个斐波那契数结尾的斐波那契数列组成一个新的以第i+1个斐波那契数结尾的斐波那契数列。需要注意的两点是:1.为了把斐波那契数和它在斐波那契数列中的位置建立联系,我们使用了unordered_map。2.如果遇到的数为1,则1既可以作为第2个斐波那契数,也可以作为第一个斐波那契数,因此在代码中要: count[ 2 ] += count[ 1 ];  count[ 1 ]++;。

递归代码如下:

#include <iostream>
#include <vector>
using namespace::std;
void helper(long long& ret, vector<int>& nums, int pre, int start, int find) {
    int n = (int)nums.size();
    ret %= 1000000007; // 防止long long溢出
    if (start==n) {
        return;
    }
    for (int i=start; i<n; i++) {
        if (nums[i]==find) {
            helper(++ret, nums, find, i+1, pre+find); //继续往下搜索
        }
    }
}
int main() {
    int n;
    cin >> n;
    vector<int> nums(n, 0);
    for (int i=0; i<n; i++) {
        cin >> nums[i];
    }
    long long res = 0;
    int pre = 0;
    helper(res, nums, pre, 0, 1);
    cout << res%1000000007 << endl;
}
DP代码为:

#include <iostream>
#include <unordered_map>
using namespace std;

int main()
{
    unordered_map<int, int> uMap;
    int f[30] = {0, 1};
    uMap[0] = 0;
    uMap[1] = 1;
    for (int i=2; i<30; i++) {
        f[i] = f[i-1]+f[i-2];
        if (f[i]>100000) {
            break;
        }
        uMap[f[i]] = i;
    }
    int n, num;
    cin >> n;
    long long count[30] = {0};
    for (int i=0; i<n; i++) {
        cin >> num;
        if (num==1) {
            count[2] += count[1];
            count[1]++;
        } else if(uMap.count(num)) {
            count[uMap[num]] += count[uMap[num]-1];
        }
        
    }
    long long res = 0;
    for (int i=1; i<30; i++) {
        res += count[i]%1000000007;
    }
    cout << res%1000000007 << endl;
    return 0;
}

题目4 : Image Encryption

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

A fancy square image encryption algorithm works as follow:

0. consider the image as an N x N matrix

1. choose an integer k∈ {0, 1, 2, 3}

2. rotate the square image k * 90 degree clockwise

3. if N is odd stop the encryption process

4. if N is even split the image into four equal sub-squares whose length is N / 2 and encrypt them recursively starting from step 0

Apparently different choices of the k serie result in different encrypted images. Given two images A and B, your task is to find out whether it is POSSIBLE that B is encrypted from A. B is possibly encrypted from A if there is a choice of k serie that encrypt A into B.

输入

Input may contains multiple testcases.

The first line of the input contains an integer T(1 <= T <= 10) which is the number of testcases.

The first line of each testcase is an integer N, the length of the side of the images A and B.

The following N lines each contain N integers, indicating the image A.

The next following N lines each contain N integers, indicating the image B.

For 20% of the data, 1 <= n <= 15

For 100% of the data, 1 <= n <= 100, 0 <= Aij, Bij <= 100000000

输出

For each testcase output Yes or No according to whether it is possible that B is encrypted from A.

样例输入
3
2
1 2
3 4
3 1
4 2
2
1 2
4 3
3 1
4 2
4
4 1 2 3
1 2 3 4
2 3 4 1
3 4 1 2
3 4 4 1
2 3 1 2
1 4 4 3
2 1 3 2
样例输出
Yes
No
Yes

这道题,是道搜索题,有两个需要注意的点。1.当n>2且为偶数时,进行dfs。2.矩阵A通过顺时针旋转得到矩阵B,A中元素与B中元素的映射关系。代码如下:

#include <iostream>
#include <vector>
using namespace std;
int mat1[100][100];
int mat2[100][100];
//当n为奇数或者2时,判断矩阵A(最左上角的坐标为i, j)能否通过顺时针旋转得到矩阵B(最左上角的坐标为p,q)
bool ifEncry(int n, int i, int j, int p, int q) {
    vector<int> t;
    for (int a=p; a<p+n; a++) {
        for (int b=q; b<q+n; b++) {
            t.push_back(mat2[a][b]);
        }
    }

    //0度
    int cnt = 0, flag = 1;
    for (int a=i; a<i+n&&flag; a++) {
        for (int b=j; b<j+n; b++) {
            if (mat1[a][b]!=t[cnt++]) {
                flag = 0;
                break;
            }
        }
    }
    if (flag) {
        return true;
    }
 
    //90度
    cnt = 0, flag = 1;
    for (int a=j; a<j+n&&flag; a++) {
        for (int b=i+n-1; b>=i; b--) {
            if (mat1[b][a]!=t[cnt++]) {
                flag = 0;
                break;
            }
        }
    }
    if (flag) {
        return true;
    }
    
    //180度
    cnt = 0, flag = 1;
    for (int a=i+n-1; a>=i&&flag; a--) {
        for (int b=j+n-1; b>=j; b--) {
            if (mat1[a][b]!=t[cnt++]) {
                flag = 0;
                break;
            }
        }
    }
    if (flag) {
        return true;
    }
    //270度
    cnt = 0, flag = 1;
    for (int a=j+n-1; a>=j&&flag; a--) {
        for (int b=i; b<i+n; b++) {
            if (mat1[b][a]!=t[cnt++]) {
                flag = 0;
                break;
            }
        }
    }
    if (flag) {
        return true;
    }
    
    return false;
    
}
bool helper(int n, int i, int j, int p, int q) {
    if (n%2||n==2) {
        return ifEncry(n, i, j, p, q);
    }
    int m = n/2;
    if (helper(m, i, j, p, q)&&helper(m, i, j+m, p, q+m)&&helper(m, i+m, j, p+m, q)&&helper(m, i+m, j+m, p+m, q+m)) {
        return true;
    }
    if (helper(m, i, j, p, q+m)&&helper(m, i, j+m, p+m, q+m)&&helper(m, i+m, j, p, q)&&helper(m, i+m, j+m, p+m, q)) {
        return true;
    }
    if (helper(m, i, j, p+m, q+m)&&helper(m, i, j+m, p+m, q)&&helper(m, i+m, j, p, q+m)&&helper(m, i+m, j+m, p, q)) {
        return true;
    }
    if (helper(m, i, j, p+m, q)&&helper(m, i, j+m, p, q)&&helper(m, i+m, j, p+m, q+m)&&helper(m, i+m, j+m, p, q+m)) {
        return true;
    }
    return false;
    
}
int main() {
    
    int T, n;
    cin >> T;
    for (int i=0; i<T; i++) {
        cin >> n;
        for (int j=0; j<n; j++) {
            for (int k=0; k<n; k++) {
                cin >> mat1[j][k];
            }
        }
        for (int j=0; j<n; j++) {
            for (int k=0; k<n; k++) {
                cin >> mat2[j][k];
            }
        }
        if (helper(n, 0, 0, 0, 0))
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值