个人博客http://www.kindkidll.com/index.php/archives/157/

A-牛牛和牛可乐的赌约

知识点:概率计算

求其对立事件的概率。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 100010;

int t;
LL n, m;
LL fast_pow(LL a, LL n) {
    LL ret = 1;
    while(n) {
        if(n & 1) ret = ret * a % mod;
        a = a * a % mod;
        n /= 2;
    }
    return ret;
}
int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%lld%lld", &n, &m) ;
        n = fast_pow(n, m);
        printf("%lld\n", (n - 1)*fast_pow(n, mod - 2) % mod);
    }
    return 0;
}

B-牛牛和牛可乐的赌约2

知识点:博弈论

根据必胜态和必败态的关系可得出,当时为必败态。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 100010;

int t;
LL n, m;
int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%lld%lld", &n, &m) ;
        if(n % 3 == m % 3) puts("awsl");
        else puts("yyds");
    }
    return 0;
}

C-单词记忆方法

知识点:模拟

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 100010;

stack<int> st;
int match[MAXN];
char s[MAXN];
int getnum(char c) {
    if(isdigit(c)) return c - '0';
    return c - 'A' + 1;
}
LL solve(int l, int r) {
    LL ret = 0;
    while(l <= r) {
        if(s[l] == '(') {
            LL tmp = solve(l + 1, match[l] - 1);
            l = match[l] + 1;

            LL num = 0;
            while(l <= r && isdigit(s[l])) {
                num = num * 10 + getnum(s[l]);
                l++;
            }

            if(num) ret += tmp * num;
            else ret += tmp;
        } else {
            if(l + 1 <= r && isdigit(s[l + 1])) {
                int tmp = getnum(s[l++]);
                LL num = 0;
                while(l <= r && isdigit(s[l])) {
                    num = num * 10 + getnum(s[l]);
                    l++;
                }
                ret += tmp * num;
            } else ret += getnum(s[l++]);
        }
    }
    return ret;
}
int main() {
    scanf("%s", s);
    int len = strlen(s);
    for(int i = 0; i < len; i++) {
        if(s[i] == '(') st.push(i);
        else if(s[i] == ')') {
            match[st.top()] = i;
            st.pop();
        }
    }
    printf("%lld\n", solve(0, len - 1));
    return 0;
}

D-位运算之谜

知识点:位运算

不合法情况:

#include <map>1
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 100010;

int t;
LL x, y;
int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%lld%lld", &x, &y);
        LL ans = x - 2 * y;
        if(ans < 0 || ans & y) puts("-1") ;
        else printf("%lld\n", ans);
    }
    return 0;
}

E-会当凌绝顶,一览众山小

知识点:线段树、二分

将山峰按坐标排序之后使用线段树维护最大值最小值和对应的下标。

  • 对于右边,直接对区间进行查询和修改操作。
  • 对于左边,对区间进行操作,二分求解的值。
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 1e6 + 117;

int n;
int now[MAXN];
struct mountain {
    int id;
    int x, h;
    bool operator <(const mountain &r)const {
        return x < r.x;
    }
} a[MAXN];
///线段树
struct node {
    int l, r;
    int mx, mxid;
    int mn, mnid;
} tree[MAXN];
void to_up(int i) {///更新区间最大值和最小值
    ///同大时取右区间的
    if(tree[i * 2].mx > tree[i * 2 + 1].mx) {
        tree[i].mx = tree[i * 2].mx;
        tree[i].mxid = tree[i * 2].mxid;
    } else {
        tree[i].mx = tree[i * 2 + 1].mx;
        tree[i].mxid = tree[i * 2 + 1].mxid;
    }
    ///同小时取左区间的
    if(tree[i * 2].mn <= tree[i * 2 + 1].mn) {
        tree[i].mn = tree[i * 2].mn;
        tree[i].mnid = tree[i * 2].mnid;
    } else {
        tree[i].mn = tree[i * 2 + 1].mn;
        tree[i].mnid = tree[i * 2 + 1].mnid;
    }
}
void build(int i, int l, int r) {///构建线段树
    tree[i].l = l;
    tree[i].r = r;
    if(l == r) {
        tree[i].mxid = tree[i].mnid = l;
        tree[i].mx = tree[i].mn = a[l].h;
        return;
    }
    int mid = (l + r) / 2;
    build(i * 2, l, mid);
    build(i * 2 + 1, mid + 1, r);
    to_up(i);
}
void update(int i, int p, int x) {///p点的值更新为x
    if(tree[i].l == tree[i].r) {
        tree[i].mx = tree[i].mn = x;
        return;
    }
    int mid = (tree[i].l + tree[i].r) / 2;
    if(p <= mid) update(i * 2, p, x);
    else update(i * 2 + 1, p, x);
    to_up(i);
}
int querymx(int i, int l, int r) {
    ///返回区间最大值的下标
    ///多个最大值返回最右边的
    ///返回0为不合法情况
    if(l > r) return 0;
    if(l <= tree[i].l && tree[i].r <= r) return tree[i].mxid;

    int ret = 0;
    int mid = (tree[i].l + tree[i].r) / 2;
    if(l <= mid) {
        int id = querymx(i * 2, l, r);
        if(ret == 0 || a[id].h > a[ret].h) ret = id;
    }
    if(r > mid) {
        int id = querymx(i * 2 + 1, l, r);
        if(ret == 0 || a[id].h >= a[ret].h) ret = id;
    }
    return ret;
}
int querymn(int i, int l, int r) {
    ///返回区间最小值的下标
    ///多个最小值返回最左边的
    ///返回0为不合法情况
    if(l > r) return 0;
    if(l <= tree[i].l && tree[i].r <= r) return tree[i].mnid;

    int ret = 0;
    int mid = (tree[i].l + tree[i].r) / 2;
    if(l <= mid) {
        int id = querymn(i * 2, l, r);
        if(ret == 0 || a[id].h < a[ret].h) ret = id;
    }
    if(r > mid) {
        int id = querymn(i * 2 + 1, l, r);
        if(ret == 0 || a[id].h < a[ret].h) ret = id;
    }
    return ret;
}
int erfen(int l, int r, int i) {
    while(l <= r) {
        int mid = (l + r) / 2;
        int id = querymx(1, mid, i - 1);
        if(a[id].h > a[i].h) l = mid + 1;
        else r = mid - 1;
    }
    return r;
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d%d", &a[i].x, &a[i].h);
        a[i].id = i;
    }
    ///按坐标排序并建立排序前后的下标关系
    sort(a + 1, a + n + 1);
    build(1, 1, n);
    for(int i = 1; i <= n; i++) now[a[i].id] = i;

    for(int j = 1; j <= n; j++) {
        int i = now[j];
        ///处理左边
        int id = erfen(1, i - 1, i);
        if(id) {
            a[id].h = a[i].h;
            update(1, id, a[i].h);
        }
        ///处理右边
        id = querymx(1, i + 1, n);
        if(id != 0 && a[id].h <= a[i].h) {
            id = querymn(1, i + 1, n);
            a[id].h = a[i].h;
            update(1, id, a[i].h);
        }
    }
    ///输出最终结果
    for(int i = 1; i <= n; i++) printf("%d ", a[now[i]].h);
    return 0;
}

F-牛牛的健身运动

知识点:三分

将器材两两组合得到所有可能的值,三分天数找到能增加的最大力量值。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 4e6 + 117;
const int MAXM = 4e6 + 117;

int n, tot;
LL m;
LL a[2020], b[2020];
LL aa[MAXN], bb[MAXN];
LL getnum(int k) {
    LL ret = (LL)INF * INF * 4;
    for(int i = 0; i < tot; i++) ret = min(ret, aa[i] * k + bb[i]);
    return ret;
}
LL sanfen(int l, int r) {
    while(l < r) {
        int midl = l + (r - l) / 3;
        int midr = r - (r - l) / 3;
        if(getnum(midl) > getnum(midr)) r = midr - 1;
        else l = midl + 1;
    }
    return getnum(l);
}
int main() {
    scanf("%d%lld", &n, &m);
    for(int i = 0; i < n; i++) scanf("%lld%lld", &a[i], &b[i]);
    for(int i = 0; i < n; i++) {
        for(int j = i + 1; j < n; j++) {
            aa[tot] = a[i] + a[j];
            bb[tot++] = b[i] + b[j];
        }
    }
    printf("%lld\n", sanfen(1, m));
    return 0;
}

G-牛牛和字符串的日常

知识点:KMP算法

给定一个模式串,求在主串中最长能匹配多少,KMP模板题。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 100010;

int n;
int len, m;
char s[MAXN], t[MAXN];
int ans, kmpNext[MAXN];
void preKMP() {
    int i = 0, j = kmpNext[0] = -1;
    while(i < len) {
        while(-1 != j && s[i] != s[j]) j = kmpNext[j];
        if(s[++i] == s[++j]) kmpNext[i] = kmpNext[j];
        else kmpNext[i] = j;
    }
}
int main() {
    scanf("%s%d", s, &n);
    len = strlen(s);
    preKMP();
    while(n--) {
        scanf("%s", t);
        m = strlen(t);
        int num = 0, i = 0, j = 0;
        while(i < m) {
            while(-1 != j && t[i] != s[j]) j = kmpNext[j];
            i++, j++;
            num = max(num, j);
        }
        ans += num;
    }
    printf("%d\n", ans);
    return 0;
}

H-上学要迟到了

知识点:最短路

关键在于理解题意,相邻的车站建立双向边,公交车的运行线路建立单向边,然后跑最短路。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 100010;

int n, m, s, t, T;
int tt[MAXN], a[MAXN], idex[MAXN];
///建图
struct Edge {
    int v, w, ne;
} edge[MAXN];
int head[MAXN], tot;
void addedge(int u, int v, int w) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].ne = head[u];
    head[u] = tot++;
}
///最短路
struct qnode {
    int v, w;
    qnode(int _v = 0, int _w = 0): v(_v), w(_w) {}
    bool operator <(const qnode &r)const {
        return w > r.w;
    }
};
bool vis[MAXN];
int dist[MAXN];
void Dijkstra() {
    memset(vis, false, sizeof(vis));
    memset(dist, INF, sizeof(dist));
    priority_queue<qnode> que;
    dist[s] = 0;
    que.push(qnode(s, 0));
    qnode tmp;
    while(!que.empty()) {
        tmp = que.top();
        que.pop();
        int u = tmp.v;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = head[u]; i != -1; i = edge[i].ne) {
            int v = edge[i].v;
            int w = edge[i].w;
            if(!vis[v] && dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                que.push(qnode(v, dist[v]));
            }
        }
    }
}
int main() {
    tot = 0;
    memset(head, -1, sizeof(head));

    scanf("%d%d%d%d%d", &n, &m, &s, &t, &T);
    for(int i = 1; i <= m; i++) scanf("%d", &tt[i]);
    for(int i = 1; i <= n; i++) {
        if(i > 1) addedge(i, i - 1, T);
        if(i < n) addedge(i, i + 1, T);
        scanf("%d", &a[i]);
        if(idex[a[i]]) addedge(idex[a[i]], i, tt[a[i]]);
        idex[a[i]] = i;
    }
    Dijkstra();
    printf("%d\n", dist[t]);
    return 0;
}

I-迷宫

知识点:dp

每个格子的状态只有种,遍历一遍网格并更新网格的状态。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 1e6 + 117;

int n, m;
int p = 10007;
int a[100][100];
bool dp[100][100][10007];
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            scanf("%d", &a[i][j]);
            a[i][j] %= p;
            if(i == 0 && j == 0) dp[i][j][a[i][j]] = true;
            for(int k = 0; k < p; k++) {
                if(dp[i][j][k] == 0) continue;
                if(i < n - 1) dp[i + 1][j][(k + a[i][j]) % p] = true;
                if(j < m - 1) dp[i][j + 1][(k + a[i][j]) % p] = true;
            }
        }
    }
    int cnt = 0;
    for(int i = 0; i < p; i++)
        if(dp[n - 1][m - 1][i]) cnt++;
    printf("%d\n", cnt);
    return 0;
}

J-树上行走

知识点:并查集

并查集处理之后输出答案即可。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const LL mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 1e6 + 117;

int n;
int a[MAXN];
struct Edge {
    int v, ne;
} edge[MAXN];
int head[MAXN], tot;
void addedge(int u, int v) {
    edge[tot].v = v;
    edge[tot].ne = head[u];
    head[u] = tot++;
}

int ans, num;
int root[MAXN], cnt[MAXN];
bool vis[MAXN];
void dfs(int id, int r) {
    root[id] = r;
    vis[id] = true;
    for(int i = head[id]; i != -1; i = edge[i].ne) {
        int v = edge[i].v;
        if(!vis[v] && a[v] == a[r]) dfs(v, r);
    }
}
int main() {
    ///初始化
    ans = num = tot = 0;
    memset(vis, false, sizeof(vis));
    memset(head, -1, sizeof(head));
    memset(cnt, 0, sizeof(cnt));
    ///建图
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for(int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    ///并查集
    for(int i = 1; i <= n; i++)
        if(!vis[i]) dfs(i, i);
    ///计算答案
    for(int i = 1; i <= n; i++) {
        cnt[root[i]]++;
        ans = max(ans, cnt[root[i]]);
    }
    for(int i = 1; i <= n; i++ )
        if(cnt[root[i]] == ans) num++;
    printf("%d\n", num);
    for(int i = 1; i <= n; i++)
        if(cnt[root[i]] == ans) printf("%d ", i);
    return 0;
}