1. 程式人生 > >招商銀行信用卡中心2019秋招IT筆試(AI、開發、測試開發方向)第二批

招商銀行信用卡中心2019秋招IT筆試(AI、開發、測試開發方向)第二批

X遊戲

題目

我們稱一個數X 為好數, 如果它的每位數字逐個地被旋轉 180 度後,我們仍可以得到一個有效的,且和 X 不同的數。要求每位數字都要被旋轉。

如果一個數的每位數字被旋轉以後仍然還是一個數字, 則這個數是有效的。0, 1, 和 8 被旋轉後仍然是它們自己;25 可以互相旋轉成對方;69 同理,除了這些以外其他的數字旋轉以後都不再是有效的數字。

現在我們有一個正整數 N, 計算從 1 到 N 中有多少個數 X 是好數?

輸入描述:

輸入正整數N

輸出描述:

輸出1到N中好數個數

樣例:

10
>--------------------------------------------------<
4

解析

資料不大的時候模擬就行了;

資料很大的時候就要數位DP了,這裡就不細說了。

#include <bits/stdc++.h>

int main()
{
    for (int n; std::cin >> n;) {
        int ans = 0;
        for (int i = 1; i < n + 1; ++i) {
            std::string str = [] (int n) -> std::string{
                std::string ret;
                for
(; n; ret.push_back(n % 10 + '0'), n /= 10) {} return ret; }(i); std::all_of(std::begin(str), std::end(str), [] (const char c) { return c != '3' && c != '4' && c != '7'; }) && std::any_of(std::begin
(str), std::end(str), [] (const char c) { return c == '2' || c == '5' || c == '6' || c == '9'; }) ? ++ans : 0; } std::cout << ans << std::endl; } return 0; }

跳格子游戲

題目

假設你正在玩跳格子(所有格子排成一個縱列)遊戲。需要 跳完n 個格子你才能抵達終點。
每次你可以跳 12 個格子。你有多少種不同的方法可以到達終點呢?
注意:給定n是一個正整數。

輸入描述:

格子數n

輸出描述:

跳完n個格子到達終點的方法

樣例:

2
>--------------------------------------------------<
2

解析

斐波拉契數列;

#include <bits/stdc++.h>

int main()
{
    for (int n; std::cin >> n; ) {
        long long f0 = 1, f1 = 1, t;
        for (int i = 2; i <= n; t = f1, f1 += f0, f0 = t, ++i) {}
        std::cout << f1 << std::endl;
    }
    return 0;
}

糖果分配

題目

假設你是一位很有愛的幼兒園老師,想要給幼兒園的小朋友們一些小糖果。但是,每個孩子最多隻能給一塊糖果。對每個孩子i,都有一個胃口值 gi ,這是能讓孩子們滿足胃口的糖果的最小尺寸;並且每塊糖果j,都有一個尺寸sj。如果 sj >= gi ,我們可以將這個糖果j分配給孩子i,這個孩子會得到滿足。你的目標是儘可能滿足越多數量的孩子,並輸出這個最大數值。

注意:

你可以假設胃口值為正。

一個小朋友最多隻能擁有一塊糖果。

輸入描述:

第一行輸入每個孩子的胃口值

第二行輸入每個糖果的尺寸

孩子數和糖果數不超過1000

輸出描述:

能滿足孩子數量的最大值

樣例:

1 2 3
1 1
>--------------------------------------------------<
1

解析

貪心,儘量讓每個孩子得到剛好合適的糖果。

#include <bits/stdc++.h>

int main()
{
    std::string cindyString, childString;
    std::getline(std::cin, childString);
    std::getline(std::cin, cindyString);
    std::vector<int> cindys, childs;
    auto stringInput = [] (const std::string & str, std::vector<int> & vec) {
        std::stringstream sin(str);
        for (int x; sin >> x; vec.emplace_back(x)) {}
    };
    stringInput(childString, childs);
    stringInput(cindyString, cindys);
    std::sort(std::begin(cindys), std::end(cindys));
    std::sort(std::begin(childs), std::end(childs));
    int ans = 0;
    for (auto it = std::begin(childs), start = std::begin(cindys);
         it != std::end(childs) && start != std::end(cindys); ++it) {
        auto pos = std::lower_bound(start, std::end(cindys), *it);
        if (pos != std::end(cindys)) {
            ++ans;
            start = pos + 1;
        } else
            start = pos;
    }
    std::cout << ans << std::endl;
    return 0;
}

K點遊戲

題目

小招喵某日閒來無事,想驗一下自己的人品,於是給自己定了一個遊戲規則:

這個遊戲有三個因素:N,K,W

遊戲開始的時候小招喵有0點,之後如果發現自己手上的點不足K點,就隨機從1W的整數中抽取一個(包含1W),抽到哪個數字的概率都是相同的。

重複上述過程,直到小招喵獲得了K或者大於K點,就停止獲取新的點,這時候小招喵手上的點小於等於N的概率是多少?

輸入描述:

輸入為3個整數,分別對應N,K,W,中間用空格隔開

其中0 <= K <= N <= 100001 <= W <= 10000

輸出描述:

輸出為概率值,保留5位小數

樣例:

21 17 10
>--------------------------------------------------<
0.73278

解析

列舉最後一次取之前已經取了多少點,然後看看還要取多少點能滿足>= K並且<= N就行了。

最後一次取了x點的概率可以用記憶化搜尋弄出來。

這題比較坑的地方在於保留5位小數,像程式碼中特殊處理一下才能過這個題。

#include <bits/stdc++.h>

double dfs(int sum, int w, std::vector<double> & dp)
{
    if ((int)dp[sum] + 1)
        return dp[sum];
    double ret = 0;
    for (int i = 1; i <= w && i <= sum; ++i) {
        double s = dfs(sum - i, w, dp) / w;
        ret += s;
    }
    return dp[sum] = ret;
}

int main()
{
    for (int n, k, w; std::cin >> n >> k >> w; ) {
        double ans = 0;
        std::vector<double> dp(k + 1, -1);
        dp[0] = 1;
        for (int pre = 0; pre < k; ++pre) {
            if (k - pre > w) continue;
            ans += dfs(pre, w, dp) * ((std::min(n - pre, w) - (k - pre) + 1.0) / w);
        }
        std::stringstream sout;
        sout << std::setprecision(5) << ans;
        std::cout << sout.str().substr(0, 7) << std::endl;
    }
    return 0;
}

排隊唱歌

題目

我們部門要排隊唱歌,大家亂哄哄的擠在一起,現在需要按從低到高的順序拍成一列,但每次只能交換相鄰的兩位,請問最少要交換多少次

輸入描述:

第一行是NN<50000),表示有N個人

然後每一行是人的身高HiHi<2000000,不要懷疑,我們以微米計數),持續N行,表示現在排列的隊伍

輸出描述:

輸出一個數,代表交換次數。

樣例:

6
3
1
2
5
6
4
>--------------------------------------------------<
4

解析

這題翻譯過來就是,氣泡排序交換的次數,答案是序列的逆序對數。如何求逆序對呢?請參考序列逆序對問題詳解

這題的程式碼就是上面部落格的程式碼。

#include <bits/stdc++.h>

class Solution {
public:
    int InversePairs(std::vector<int> data) {
        std::vector<int> pos(data.size()), arr(data);
        sort(data.begin(), data.end());
        for (int i = 0; i < (int)pos.size(); i++)
            pos[i] = lower_bound(data.begin(), data.end(), arr[i]) - data.begin();

        int c[(const int)data.size() + 1];
        memset(c, 0, sizeof(c));
        long long ret = 0;
        for (int i = 0; i < (int)data.size(); i++)
            add(c, pos[i] + 1, data.size()),
                    ret = (ret + i + 1 - getsum(c, pos[i] + 1));
        return (int)ret;
    }

    int lowbit(int x)
    {
        return x & -x;
    }

    long long getsum(int c[], int i)
    {
        long long ret = 0;
        for (; i > 0; i -= lowbit(i))
            ret = (ret + c[i]);
        return ret;
    }

    void add(int c[], int i, int n)
    {
        for (; i <= n; i += lowbit(i))
            ++c[i];
    }

};

int main()
{
    for (int n; std::cin >> n;) {
        std::vector<int> arr(n);
        for (int i = 0; i < n; std::cin >> arr[i++]) {}
        Solution sol;
        std::cout << sol.InversePairs(arr) << std::endl;
    }
    return 0;
}