Teacher Ma专场

A: 不讲武德

关于题意题目讲的很清楚了

思路:可以利用Python的大数类,或者使用C++ string类进行累加

// 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来

想了很久,应该是马拉车算法解,但没想到怎么处理

用马拉车算法求出 p 数组,然后处理原字符串以每个位置结尾的回文串的个数,然后求前缀和进行枚举,利用前面求取的前缀和就可以知道右端在当前回文串左端的左侧回文串个数,统计的枚举结果即答案。

关于马拉车算法可以看这里: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题给我爬

咳咳,,不闹了。这道题需要枚举两个健身房是否可达,利用并查集维护。最后输出集合大小即可。但是这道题其实只能暴力做?:(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区间的野怪所受伤害。

// 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;
}
原文地址:https://www.cnblogs.com/RioTian/p/14070410.html