Bootstrap

2024牛客暑期多校1(新手题)

H-World Finals

原题:H-World Finals_2024牛客暑期多校训练营1 (nowcoder.com)icon-default.png?t=N7T8https://ac.nowcoder.com/acm/contest/81596/H

题目大意:

有两场World Finals同时举办,每场都有若干出线队伍,两场出线名单可能有重复的队伍,而一个队伍只能选择其中的一场参加,然后每场比赛的每支队伍都有一个预测成绩(过题数+ 罚时)lzr010506在两场World Finals 都出线了,他想知道如果所有队伍的最终成绩就是预测成绩,并且可以任意分配两场都出线了队伍的比赛场次的选择,他们队最高可能的排名是多少(1 ≤ number of teams ≤ 10^5)

题解:

两种情况:1、“lzr010506”参加第一场,其他比他强的在第二场;2、“lzr010506”参加第二场,其他比他强的在第一场。两种情况取最优即可。

代码片段:

struct t {
    string name;
    int problem;
    int time;
};
 
bool cmp(t x, t y) {
    if (x.problem == y.problem) return x.time < y.time;
    return x.problem > y.problem;
}
 
map<string, int> a;
int m, n, e1, i, j, w1, w2, w, ans1, ans2, sum;
string e[100005];
 
void solve() {
    cin >> n;
    vector<t> c(n);
    for (i = 0; i < n; i++) {
        cin >> c[i].name >> c[i].problem >> c[i].time;
        a[c[i].name]++;
    }
    cin >> m;
    vector<t> d(m);
    for (i = 0; i < m; i++) {
        cin >> d[i].name >> d[i].problem >> d[i].time;
        a[d[i].name]++;
    }
    for (auto i: a) {
        if (i.second == 2) {
            e[e1] = i.first;
            e1++;
        }
    }
    sort(c.begin(), c.end(), cmp);
    sort(d.begin(), d.end(), cmp);
 
    for (i = 0; i < n; i++) {
        if (c[i].name == "lzr010506") {
            w1 = i;
            break;
        }
    }
    for (i = 0; i < m; i++) {
        if (d[i].name == "lzr010506") {
            w2 = i;
            break;
        }
    }
 
    unordered_set<string> res(e, e + e1);
    for (i = 0; i < w1; i++) {
        if (res.count(c[i].name)) {
            ans1++;
        }
    }
    for (i = 0; i < w2; i++) {
        if (res.count(d[i].name)) {
            ans2++;
        }
    }
 
    sum = min(w1 - ans1, w2 - ans2);
    cout << sum + 1 << endl;
}

C-Sum of Suffix Sums

C-Sum of Suffix Sums_2024牛客暑期多校训练营1 (nowcoder.com)icon-default.png?t=N7T8https://ac.nowcoder.com/acm/contest/81596/C

题目大意:

一个初始为空的非负整数序列,支持q次操作,每次操作移除末尾的若干个整数,然后在末尾加入一个整数v,每次操作后输出当前序列所有后缀和的总和,答案对1e9+7取模(1 ≤ q ≤ 5×1e5, 0 ≤ v ≤ 1e9)

题解:

ai 会出现在所有起始位置≤i的后缀和里,在总和里出现i次,总和就是i×ai

代码:

void solve() {
    int q;
    cin >> q;
    vector<ll> pre;
    long long sum = 0;

    while (q--) {
        int t;
        ll v;
        cin >> t >> v;
        while (t-- > 0 && !pre.empty()) {
            sum = (sum - pre.back() + MOD) % MOD;
            pre.pop_back();
        }

        sum = (sum + v) % MOD;
        if (!pre.empty()) {
            pre.push_back((pre.back() + v) % MOD);
        } else {
            pre.push_back(v);
        }
        cout << sum << endl;
    }
}

A-A Bit Common

原题:A-A Bit Common_2024牛客暑期多校训练营1 (nowcoder.com)icon-default.png?t=N7T8https://ac.nowcoder.com/acm/contest/81596/A

题目大意:

有多少长为n的元素在[0,2^m)的整数序列满足:存在一个非空子序列的AND和是1,答案对输入的正整数q取模(1≤n,m≤5000),1≤q≤1e9。

思路:

首先注意q不一定是质数!!!

AND和为1==>最后一位是1,其他位每位至少1个0

在n个数里选择k个作为AND和为1的目标子序列,其他的最后一位是0,前面任意

公式:C(k,n)×2^((m-1)(n-k))×(2^k-1)^(m-1)

代码片段:

int ar[maxn], top;
int mod;

int add(int a, int b) {
    return ((a += b) >= mod) ? a - mod : a;
}

int mul(int x, int y) {
    return (ll) x * y % mod;
}

int C[maxn];

void init(int n) {
    for (int i = 1; i <= n; ++i) C[i] = 0;
    C[0] = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = i; j; --j) {
            C[j] = add(C[j], C[j - 1]);
        }
    }
}

int fpow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b & 1) ans = mul(ans, a);
        a = mul(a, a);
        b >>= 1;
    }
    return ans;
}

void solve() {
    ll n, m;
    cin >> n >> m >> mod;
    if (mod == 1) {
        cout << '0' << endl;
        return;
    }
    init(n);
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        int a = add(fpow(2, i), mod - 1);
        a = fpow(a, m - 1);
        int b = (m - 1) * (n - i) % (mod - 1);
        b = fpow(2, b);
        a = mul(a, b);
        a = mul(a, C[i]);
        ans = add(ans, a);
    }
    cout << ans << endl;
}

I - Mirror Maze

I-Mirror Maze_2024牛客暑期多校训练营1 (nowcoder.com)icon-default.png?t=N7T8https://ac.nowcoder.com/acm/contest/81596/I

题目大意:

有一个n×m的矩形镜子迷宫,镜子有“\, /, -, |” 四种,有q个询问,每个询问给定一个点光源(x, y, dir),表示在(x, y) 位置向dir方向发射一束光线,问这束光线被多少个不同的镜子反射过。(1≤n, m≤1000, 1≤q≤1e5)

思路:

对于每一种状态(x,y,dir),无论之前是怎么过来的,经过他之后的路径就是一定的了
dfs,因为经过了之后后面有多少点就求过一次了,状态就是4mn
特殊:在同一个圈内的次数一致,在圈外的是后继节点+1(后继节点为反射前一次,与中途未经反射的镜子数无关)

代码片段:

int n, m, i, j, Q, tt;
int mp[1005][4], a[1005][1005], v[1005][1005][4], ans[1005][1005][4], fs[1005][1005];
int dx[4], dy[4];
string s;
string t;
vector<tuple<int, int, int, int>> q;
vector<pair<int, int>> vv;

void dfs(int x, int y, int d) {
    if (x < 1 || y < 1 || x > n || y > m) {
        ans[x][y][d] = 0;
        return;
    }
    if (v[x][y][d]) {
        tt = 1;
        return;
    }
    int nxt = mp[a[x][y]][d];
    v[x][y][d] = 1;
    q.push_back({x, y, d, d != nxt});
    x += dx[nxt];
    y += dy[nxt];
    dfs(x, y, nxt);
}

void trys(int x, int y, int d) {
    tt = 0;
    q = {};
    vv = {};
    if (x < 1 || y < 1 || x > n || y > m) {
        ans[x][y][d] = 0;
        return;
    }
    dfs(x, y, d);
    reverse(q.begin(), q.end());
    int sum = 0;
    if (tt) {
        for (auto [x,y,d,z]: q)
            if (z && !fs[x][y]) {
                fs[x][y] = 1;
                sum++;
                vv.push_back({x, y});
            }
        for (auto [x,y,d,z]: q) {
            ans[x][y][d] = sum;
        }
    } else {
        for (auto [x,y,d,z]: q) {
            if (z && !fs[x][y]) {
                fs[x][y] = 1;
                sum++;
                vv.push_back({x, y});
            }
            ans[x][y][d] = sum;
        }
    }
    for (auto [i,j]: vv) fs[i][j] = 0;
}

void solve() {
    int x, y, d;
    memset(ans, -1, sizeof(ans));
    dx[0] = -1;
    dx[2] = 1;
    dy[1] = 1;
    dy[3] = -1;
    mp['-'][0] = 2;
    mp['-'][1] = 1;
    mp['-'][2] = 0;
    mp['-'][3] = 3;
    mp['|'][0] = 0;
    mp['|'][1] = 3;
    mp['|'][2] = 2;
    mp['|'][3] = 1;
    mp['/'][0] = 1;
    mp['/'][1] = 0;
    mp['/'][2] = 3;
    mp['/'][3] = 2;
    mp['\\'][0] = 3;
    mp['\\'][1] = 2;
    mp['\\'][2] = 1;
    mp['\\'][3] = 0;
    cin >> n >> m;
    for (i = 0; i < n; i++) {
        cin >> s;
        for (j = 0; j < m; j++) {
            a[i + 1][j + 1] = s[j];
        }
    }
    for (i = 1; i <= m; i++) {
        trys(i, 1, 1);
        trys(i, m, 3);
    }
    for (i = 1; i <= n; i++) {
        trys(1, i, 2);
        trys(n, i, 0);
    }
    cin >> Q;
    while (Q--) {
        cin >> x >> y >> t;
        if (t == "above") {
            d = 0;
        }
        if (t == "right") {
            d = 1;
        }
        if (t == "below") {
            d = 2;
        }
        if (t == "left") {
            d = 3;
        }
        x += dx[d];
        y += dy[d];
        if (!v[x][y][d]) {
            trys(x, y, d);
        }
        cout << ans[x][y][d] << endl;
    }
}
;