太可惜了,一開始手滑完全忘記 int 乘以 int 會炸~ 第二題實在是很想用 python 寫XD

給定一個非負整數 $c$,問是否存在整數 $a$ 和 $b$ 滿足 $a^2+b^2=c$?

後來與修拉拉討論以後,發現最簡單的作法是枚舉 $a$、然後硬算 $b=\sqrt{c-a^2}$。

class Solution {
public:
    bool judgeSquareSum(int c) {
        for (long long a = 0; a*a <= c; a++) {
            long long b = sqrt(c - a*a);
            if (a*a+b*b==c) return true;
        }
        return false;
    }
};

這題有數學解的樣子:費馬的二平方和定理。若去除平方因子以後,所有的奇質因數都是形如 $4k+1$ 的話,必定有解。

class Solution {
public:
    bool judgeSquareSum(int c) {
        for (long long p=2;p*p<=c;p++)
            while (c%(p*p) == 0)
                c /= (p*p);
        if (c%2==0) c/=2;
        for (long long p=3;p*p<=c;p++)
            if (c%p==0) {
                if(p%4==3) return false;
                c/=p;
            }
        return c==0 || c%4==1;
    }
};

請你實作一個 Log 查詢系統,可以查詢某一段給定時間的 Log。

不解釋。其實可以直接用字串比對,只要比到指定長度就可以了。因為輸入不大,所以也可以暴力比較。

class LogSystem {
public:
    vector<pair<int, string>> all;
    string c[6] = {"Year", "Month", "Day", "Hour", "Minute", "Second"};
    int len[6] = {4, 7, 10, 13, 16, 19};
    LogSystem() {
        all = vector<pair<int, string>>();
    }
    
    void put(int id, string timestamp) {
        all.push_back({id, timestamp});
    }
    
    vector<int> retrieve(string s, string e, string gra) {
        int j = find(c, c+6, gra) - c;
        s = s.substr(0, len[j]);
        e = e.substr(0, len[j]);
        vector<int> res;
        for(auto it: all)
            if (it.second.substr(0, len[j]) >= s && it.second.substr(0, len[j]) <= e)
                res.push_back(it.first);
        return res;
    }
};

給定 $n$,請問 $1$ 到 $n$ 的錯置排列有幾種?請輸出答案除以 $10^9+7$ 的餘數。

經典的錯排問題。有兩種解法:排容方法是

這會等於

把前面的 $n$ 項各自提出一個 $n$,並整理成遞迴式得到:

剩下就好辦了。另外一種解法是關注 $1$ 被排到哪裡去:假設 $1$ 出現在排列的第 $k$ $(k\neq 1)$ 位,而該排列第一個數是 $k$,那麼扣除 $1$ 和 $k$ 這兩個數字以後,剩下的數字和其位置們形成一個長度為 $n-2$ 的錯排,此情形有 $(n-1)a_{n-2}$ 種。若該排列第一個數字既不是 $1$ 也不是 $k$,那麼我們將第一個數字與 $1$ 所在位置對調,現在恰好有一個不動點,也就是說剩下的 $n-1$ 個數字形成一個錯排:此情形恰好有 $(n-1)a_{n-1}$ 種。所以我們有:

是個 $n-1$ 倍的費氏數列呢!

class Solution {
public:
    int findDerangement(int n) {
        const long long MOD = 1e9+7;
        long long a=0,b=1,c;
        for(int i=2;i<=n;i++) {
            c=i*(b+a) % MOD;
            a=b;
            b=c;
        }
        return (int)a;
    }
};

給你 $k$ 個排好序的 list,請找出長度最小的區間,使得每一個 list 至少有一個數字出現在這個區間內。所有數字範圍 $[-10^5, 10^5]$,至多 $3500$ 個 list。

class Solution {
public:
    vector<int> smallestRange(vector<vector<int>>& nums) {
        set<pair<int, int>> q;
        int k = (int)nums.size();
        for(int i = 0; i < k; i++) q.insert({nums[i][0], i});
        int ans = q.rbegin()->first - q.begin()->first;
        int l = q.begin()->first, r = q.rbegin()->first;
        while(true) {
            auto obj = *q.begin();
            int i = obj.second;
            int v = obj.first;
            q.erase(q.begin());
            if(nums[i].back() == v) break;
            q.insert({*upper_bound(nums[i].begin(), nums[i].end(), v), i});
            if (ans > q.rbegin()->first - q.begin()->first) {
                ans = q.rbegin()->first - q.begin()->first;
                l = q.begin()->first, r = q.rbegin()->first;
            }
        }
        return {l, r};
    }
};