Teacher Ma專場

A: 不講武德

關於題意題目講的很清楚了html

思路:能夠利用Python的大數類,或者使用C++ string類進行累加python

// Cpp
#include <bits/stdc++.h>
using namespace std;
int _;

string add(string a, string b) {
    string res = "";
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    int len = min(a.size(), b.size());
    if (a.size() < b.size())
        swap(a, b);
    int jw = 0;  //處理進位
    for (int i = 0; i < len; ++i) {
        int x = jw + (a[i] - '0') + (b[i] - '0');
        jw = x / 10;
        x %= 10;
        res += char('0' + x);
    }
    for (int i = len; i < a.size(); i++) {
        int x = jw + (a[i] - '0');
        jw = x / 10;
        x = x % 10;
        res = res + char('0' + x);
    }
    if (jw)
        res += ('0' + jw);
    reverse(res.begin(), res.end());
    // cout<<res<<endl;
    return res;
}

bool cmp(string a, string b) {
    if (a.size() < b.size())
        return false;
    if (a.size() > b.size())
        return true;
    return a > b;
}

void solve() {
    string a, b, c;
    cin >> a >> b >> c;
    if (cmp(a, add(b, c)))
        puts("Yes");
    else
        puts("No");
}
int main() {
    // freopen("in.txt", "r", stdin);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    for (cin >> _; _; _--)
        solve();
}
# Python
t = int(input())
while (t):
    a, b, c = map(int, input().split())
    # a, b, c = int(input().split(' '))
    if (a > b + c):
        print("Yes")
    else:
        print("No")
    t -= 1

B: 有bear來

想了好久,應該是馬拉車算法解,但沒想到怎麼處理ios

用馬拉車算法求出 p 數組,而後處理原字符串以每一個位置結尾的迴文串的個數,而後求前綴和進行枚舉,利用前面求取的前綴和就能夠知道右端在當前迴文串左端的左側迴文串個數,統計的枚舉結果即答案。c++

關於馬拉車算法能夠看這裏:Here算法

// Author : RioTian
// Time : 20/12/01
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e4 + 10;
const int inf = ~0u >> 2;

char str[N];
ll p[N], sum[N];

int main() {
    // freopen("in.txt", "r", stdin);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scanf("%s", str);
    int len = strlen(str), id = 0;
    for (int i = len; i >= 0; i--) {
        str[i * 2 + 2] = str[i];
        str[i * 2 + 1] = '#';
    }
    str[0] = '*';
    for (int i = 2; i <= len * 2; ++i) {
        if (p[id] + id > i)
            p[i] =
                p[2 * id - i] > p[id] + id - i ? p[id] + id - i : p[2 * id - i];
        else
            p[i] = 1;
        while (str[i - p[i]] == str[i + p[i]])
            p[i]++;
        if (id + p[id] < i + p[i])
            id = i;
    }
    for (int i = 1; i <= len * 2; ++i) {
        if (i & 1)
            for (int j = 1; j < p[i]; j += 2)
                sum[i - j]++;
        else
            for (int j = 0; j < p[i]; j += 2)
                sum[i - j]++;
    }
    for (int i = 1; i <= len * 2; ++i)
        sum[i] += sum[i - 1];
    ll ans = 0;
    for (int i = 1; i <= (len << 1); ++i)
        if (i & 1)
            for (int j = 1; j < p[i]; j += 2)
                ans += sum[len << 1] - sum[i + j];
        else
            for (int j = 0; j < p[i]; j += 2)
                ans += sum[len << 1] - sum[i + j];
    cout << ans << endl;
}

C: 點到爲止

又是一道經典SG博弈,還好此次數據少(被我手寫答案過了2333)數組

打表完能夠發現只要 \(x mod 6 == 3\) 一定是後手贏函數

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll _, n;
string name[2] = {"Teacher Ma", "Xiao Huo Zi"};
void sovle() {
    cin >> n;
    if (n == 3 || n == 9 || n == 15)
        cout << name[1] << endl;
    else
        cout << name[0] << endl;
}
int main() {
    // freopen("in.txt", "r", stdin);
    for (cin >> _; _; _--)
        sovle();
}
// 正經SG函數寫法
// Author : RioTian
// Time : 20/12/01
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int sg[N];
ll _, n;
string name[2] = {"Teacher Ma", "Xiao Huo Zi"};

int dfs(int x) {
    if (sg[x] != -1)
        return sg[x];
    set<int> st;
    for (int i = 1; i < x; ++i) {
        if (__gcd(i, x) == 1)  //第二種選擇
            st.insert(dfs(x - i));
        if (i * 2 <= x)
            st.insert(dfs(i) ^ dfs(x - i));
    }
    int res = 0;
    while (st.count(res))
        res++;
    return sg[x] = res;
}

void sovle() {
    int x;
    cin >> x;
    if (dfs(x))
        cout << name[0] << endl;
    else
        cout << name[1] << endl;
}
int main() {
    // freopen("in.txt", "r", stdin);
    memset(sg, -1, sizeof sg);
    sg[0] = 0, sg[1] = 1;
    for (cin >> _; _; _--)
        sovle();
}

D: 渾元功法

這道題莫名錯掉了,LJ題給我爬spa

咳咳,,不鬧了。這道題須要枚舉兩個健身房是否可達,利用並查集維護。最後輸出集合大小便可。可是這道題其實只能暴力作?:\(O(n^2)\),若是用單調棧 \(O(n)\) 解決?(菜雞沒想到怎麼解指針

// Author : RioTian
// Time : 20/12/01
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1100;
int f[N], sz[N], id[N], a[N];
int find(int x) {
    return f[x] == x ? x : f[x] = find(f[x]);
}
int main() {
    // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        f[i] = i, sz[i] = 1;
    for (int i = 1, x, y; i <= n; ++i) {
        cin >> x >> y;
        id[i] = x, a[x] = y;
    }
    for (int i = 1; i <= n; ++i)
        for (int j = i + 1; j <= n; ++j)
            if (a[j] > a[i]) {
                int x = find(i), y = find(j);
                if (x != y)
                    f[x] = y, sz[y] += sz[x];
            }
    for (int i = 1; i <= n; ++i)
        cout << sz[find(id[i])] << endl;
}

E: 英國大力士

區間dp。定義狀態dp[i][j]表⽰消滅i到j區間的野怪所受傷害。code

// Author : RioTian
// Time : 20/12/01
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e3, inf = ~0u >> 2, mod = 1e9 + 7;
int dp[N][N], n, a[N], b[N];

int main() {
    // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i <= n; ++i)
        cin >> b[i];
    for (int i = 1; i <= n; ++i)
        dp[i][i] = a[i] + b[i - 1] + b[i + 1];
    for (int len = 2; len <= n; ++len) {  //枚舉長度
        for (int i = 1; i <= n; ++i) {    //枚舉區間左邊界
            int j = i + len - 1;
            if (j > n)
                continue;
            dp[i][j] = inf;
            for (int k = i; k <= j; ++k)  //枚舉最後消滅的monster
                dp[i][j] = min(dp[i][j], dp[i][k - 1] + dp[k + 1][j] + a[k] +
                                             b[i - 1] + b[j + 1]);
        }
    }
    cout << dp[1][n] << endl;
}

F: 松果彈抖散顛鞭

滑動窗口,維護雙指針找到知足條件的最小區間。

// Author : RioTian
// Time : 20/12/01
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e3, inf = ~0u >> 2, mod = 1e9 + 7;
int book[10];

int main() {
    // freopen("in.txt", "r", stdin);
    string s;
    cin >> s;
    int j = 0, mi = inf;
    for (int i = 0; i < s.length(); ++i) {
        while (j < s.length() && (!book[1] || !book[2] || !book[3]))
            book[s[j++] - '0']++;
        if (book[1] && book[2] && book[3])
            mi = min(mi, j - i);
        book[s[i] - '0']--;
    }
    if (mi == inf)
        mi = 0;
    cout << mi;
}

G: 耗子尾汁

凸包問題,能夠用andrew算法求凸包

這裏就沒貼代碼(偷懶了233)

H: 閃電五連鞭

能夠用二分或者數學方法。

二分的思路是:

在總農民次數和單我的最高次數區間中二分查找。

即:當\(mid * (n - 1) >= 總盤數\) 縮小右區間,否則縮左邊

數論方法:

// Author : RioTian
// Time : 20/12/01
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N];
int main() {
    // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    ll n, sum = 0, mx = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        sum += a[i], mx = max(mx, a[i]);
    }
    ll ans = sum / (n - 1);
    if (sum % (n - 1))
        ans++;
    cout << max(ans, mx) << endl;
}