2022年浙大城市学院新生程序设计竞赛(同步赛)

A. OP (Nowcoder48876 A)

题目大意

输出fengqibisheng, yingyueerlai!

解题思路

python最快

我错了,php直接打这个字符串就可以了

神奇的代码
print("fengqibisheng, yingyueerlai!")


B. Steel of Heart (Nowcoder48876 B)

题目大意

一个打怪模拟题

解题思路

按照题意模拟即可,用数组维护被动生效时间。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T, typename... rest>
void read(T &x, rest&... Rest) {
    read(x);
    read(Rest...);
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int la[6];

int main(void) {
    LL h1, h2;
    int n;
    read(h1, h2, n);
    for(int i = 0; i < 6; ++ i)
        la[i] = -2000;
    bool own = false;
    auto calc = [](LL x){
        long long qwq = floor((125 + 1.0 * x * 0.06) * 0.1);
        return qwq;
    };
    for(int i = 1; i <= n; ++ i){
        int m, s, k;
        scanf("%d:%d", &m, &s);
        int t = m * 60 + s;
        read(k);
        if (k == 1){
            h1 += 800;
            own = true;
        }else if (k == 2){
            h1 += h2;
        }else{
            int target;
            read(target);
            if (own && t - la[target] >= 30){
                h1 += calc(h1);
                la[target] = t;
            }
        }
    }
    write(h1, '\n');

    return 0;
}



C. Add 9 Zeros (Nowcoder48876 C)

题目大意

给定\(n\)个数字\(a_i\),问 \(a_i + 9\)不是这\(n\)个数的个数。

解题思路

mapset记录下出现的数即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    set<int> qwq;
    int n;
    cin >> n;
    for(int i = 1; i <= n; ++ i){
        int x;
        cin >> x;
        qwq.insert(x);
    }
    set<int> qaq;
    for(auto i : qwq){
        if (qwq.find(i + 9) == qwq.end())
            qaq.insert(i + 9);
    }
    cout << qaq.size() << '\n';

    return 0;
}



D. Cutting with Lines Ⅰ (Nowcoder48876 D)

题目大意

<++>

解题思路

<++>

神奇的代码



E. Cutting with Lines Ⅱ (Nowcoder48876 E)

题目大意

<++>

解题思路

<++>

神奇的代码



F. Survivor (Nowcoder48876 F)

题目大意

\(n\)名玩家,第 \(i\)名玩家初始 \(a_i\)血,每分钟扣 \(b_i\)血,对其实施回复魔法,一次回复 \(c_i\)血。

现你可以实施不超过\(k\)次恢复魔法,问 \(m\)分钟后存活玩家的最大数量。玩家血量小于等于0即死亡。

解题思路

预处理让第\(i\)名玩家在 \(m\)分钟后存活的最少实施回复魔法次数数组 \(cnt_i\),从小到大依次恢复直到超过 \(k\)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    LL m, k;
    cin >> n >> m >> k;
    vector<LL> a(n), b(n), c(n), cnt(n);
    for(auto &i : a)
        cin >> i;
    for(auto &i : b)
        cin >> i;
    for(auto &i : c)
        cin >> i;
    for(int i = 0; i < n; ++ i){
        a[i] -= m * b[i];
        if (a[i] <= 0){
            cnt[i] = (-a[i] + 1 + c[i] - 1) / c[i];
        }else {
            cnt[i] = 0;
        }
    }
    sort(cnt.begin(), cnt.end());
    int ans = 0;
    while(ans < n){
        if (k - cnt[ans] >= 0){
            k -= cnt[ans];
            ++ ans;
        }else 
            break;
    }
    cout << ans << endl;

    return 0;
}



G. Red Black Tree (Nowcoder48876 G)

题目大意

给定一个直角等腰三角形摆放的格子,初始状态下一些格子颜色为黑色。其余为红色。现在要求将最小数量的红色格子变成黑色,满足以下两个要求:

  • 黑色格子\((i,j)\)的下面两个格子 \((i + 1, j), (i + 1, j + 1)\) 颜色也必须是黑色
  • 两个相邻黑色格子\((i,j), (i, j + 1)\)的上一个格子\((i - 1, j)\)颜色也必须是黑色

问黑色格子数量的最小值。

解题思路

不考虑第二个条件的话,同一列考虑最上面(行号最小)的黑色格子,最终局面就是一些黑色直角等腰三角形的叠加。

加上第二个条件的话,造成的额外影响就是,两个相互覆盖的黑色直角三角形会融合,变成一个更大的直角等腰三角形。

模拟该过程统计答案即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

const int N = 1e6 + 8;
int maxx[N];
int yy[N], cnt;

LL calc(int n){
    return 1ll * n * (n + 1) / 2;
}

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n, k;
    cin >> n >> k;
    for(int i = 1; i <= k; ++ i){
        int x, y;
        cin >> x >> y;
        ++ cnt;
        yy[cnt] = y;
        maxx[y] = max(maxx[y], n - x + y + 1);
    }
    sort(yy + 1, yy + 1 + cnt);
    cnt = unique(yy + 1, yy + 1 + cnt) - yy - 1;
    int l = yy[1];
    int r = maxx[yy[1]];
    LL ans = 0;
    for(int i = 2; i <= cnt; ++ i){
        if (r >= yy[i]){
            r = max(r, maxx[yy[i]]);
        }else{
            ans += calc(r - l);
            l = yy[i];
            r = maxx[yy[i]];
        }
    }
    ans += calc(r - l);
    cout << ans << '\n';

    return 0;
}



H. Beautiful String (Nowcoder48876 H)

题目大意

给定一个字符串\(s\),求满足以下任意条件之一的长度为 \(n\)的各位互不相同的字符串 \(t\)的数量

  • \(t\)从左到右的字母的字典序依次增大,且 \(t_1\)(第一个字母)在 \(s\)出现过
  • \(t\)中的字母在串 \(s\)都出现过。

注意串 \(s\)和串 \(t\)都由英文前\(18\)位小写字母组成。

解题思路

考虑满足第一个条件的字符串个数。

枚举第一个字母,其在\(s\)出现过,假设是第\(i\)个英文字母,则剩下位数的方案数就是 \(\tbinom{18-i}{n-1}\)

考虑满足第二个条件的字母串个数,假设\(s\)串出现了 \(m\)种字母,个数就是\(\tbinom{m}{n} \times n!\)(阶乘就是排列数) 。

再减去同时满足一二条件的个数,其实就是\(\tbinom{m}{n}\)

因此答案就是\(\sum_{i \in s}\tbinom{18-i}{n-1} + \tbinom{m}{n} \times (n! - 1)\)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)

const int N = 18;
int cnt[N], n, m;
LL jie[20];

LL C(int n, int m){
    if (n < m || n < 0 || m < 0)
        return 0;
    return jie[n] / jie[m] / jie[n - m];
}

LL A(int n, int m){
    if (n < m || n < 0 || m < 0)
        return 0;
    return jie[n] / jie[n - m]; 
}

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);

    jie[0] = 1;
    FOR(i, 1, N + 1)
        jie[i] = jie[i - 1] * i;

    int t;
    cin >> t;
    while(t--){
        string s;
        cin >> s >> n;
        for(auto &i : s)
            cnt[i - 'a'] ++;
        LL tmp = 0;
        int cc = 0;
        for(int i = 0; i < N; ++ i)
            if (cnt[i] != 0){
                m |= (1 << i);
                ++ cc;
                tmp += C(18 - i - 1, n - 1);
            }
        tmp -= C(cc, n);
        tmp += A(cc, n);
        cout << tmp << '\n';
        for(int i = 0; i < N; ++ i)
            cnt[i] = 0;
    }

    return 0;
}


I. Digit Problem (Nowcoder48876 I)

题目大意

已知数\(x,y\)在二进制下有 \(a\)\(1\)\(b\)\(0\),其差 \(z = x - y\)\(c\)\(1\)

给一个可能的 \(x,y\)。不存在输出 \(-1\)

解题思路

构造题从简单入手。

考虑\(x\)\(y\)的所有 \(1\)都在高位,此时其\(z\)没有 \(1\)

考虑 \(y\)的最低位的 \(1\)往低位移\(1\)位,则 \(z\)会多一个 \(1\)

此时 \(b \geq c\)的时候可采用该方法构造。

考虑 \(b < c\)

假设 \(z\)\(c\)\(1\)都在低位,令\(y = x - z\),可以看成 \(y = x - (z + 1) + 1\) ,相当于把\(x\)的高\(c+1\)位的 \(1\)放到最低位,\(1\)的个数和 \(x\)一样。

注意\(a=0,b=0,a+b<=c\)的特殊情况。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int a, b, c;
    cin >> a >> b >> c;
    if (a + b <= c || (a == 0 && c != 0) || (b == 0 && c != 0))
        cout << -1 << '\n';
    else{
        if (b >= c){
            string x(a + b, '0'), y(a + b, '0');
            fill(x.begin(), x.begin() + a, '1');
            if (a > 0){
                fill(y.begin(), y.begin() + a - 1, '1');
                y[a + c - 1] = '1';
            }
            cout << x << '\n';
            cout << y << '\n';
        }else{
            string x(a + b, '0'), y(a + b, '0');
            fill(x.begin(), x.begin() + a, '1');
            fill(y.begin(), y.begin() + a, '1');
            y[a + b - c - 1] = '0';
            y.back() = '1';
            cout << x << '\n';
            cout << y << '\n';
        }
    }

    return 0;
}


J. Simple Game (Nowcoder48876 J)

题目大意

\(n\)个数字,每人每回合拿走一个数字,直至无数字剩下。\(Alice\)先手, \(Bob\)后手。最后若两人拿走数的和的差是奇数, \(Alice\)A胜,否则 \(Bob\)胜。问两者绝顶聪明的情况下谁胜。

解题思路

奇偶性的相加减,也就是模\(2\)的加减其实等效于异或,即这两个操作是一样的。

因此无论他们怎么拿,最终情况都是一样,即和是奇数就\(Alice\)胜,否则 \(Bob\)胜。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    cin >> n;
    int ans = 0;
    while(n--){
        int x;
        cin >> x;
        ans ^= (x & 1);
    }
    if (ans)
        cout << "Alice" << '\n';
    else 
        cout << "Bob" << '\n';

    return 0;
}


K. Bit (Nowcoder48876 K)

题目大意

假设当前数为\(x\),给定\(n\)个操作,操作有三种类型:

  • 给定 \(a\),令\(x = x \& a\),即与运算。
  • 给定 \(a\),令\(x = x | a\),即或运算。
  • 给定 \(a\),令\(x = x \oplus a\),即异或运算。

\(q\)个询问,每个询问给定一个 \(r\),要求从 \([0,r]\)中选定 一个数\(x\),使得该数经过这 \(n\)个操作后的数最大。

解题思路

注意到位运算,二进制位之间独立,因此依次考虑每个数位取值\(0\)\(1\)

预处理数组\(f[i][j]\)表示第 \(i\) 位取值为\(j\)\(0\)\(1\)), 经过这\(n\)次操作后变成的值。

然后就从高位开始依次考虑每位取值为 \(0\)\(1\)。取值过程考虑是否有最高位限制(不大过 \(r\)),就像数位 \(dp\)里的\(limit\)变量。

即当前位如果可取\(0,1\),且最终值,取 \(1\)的时候更大,那肯定取 \(1\),否则就取 \(0\)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

const int N = 1e5 + 8;

int n, q;
int f[35][2];
int op[N], num[N];

int cal(int type, int lv, int rv){
    if (type == 1)
        return lv & rv;
    else if (type == 2)
        return lv | rv;
    else 
        return lv ^ rv;
}

int calc(int pos, int x){
    for(int i = 1; i <= n; ++ i){
        x = cal(op[i], ((num[i] >> pos) & 1), x); 
    }
    return x;
}

int b[32], pos, ans[32];

void dfs(int pos, int limit){
    if (pos < 0)
        return;
    if (limit && b[pos] == 0){
        ans[pos] = 0;
        dfs(pos - 1, limit && (b[pos] == 0));
    }
    else{
        int g1 = f[pos][1];
        int g0 = f[pos][0];
        if (g1 > g0){
            ans[pos] = 1;
            dfs(pos - 1, limit && (b[pos] == 1));
        }else{
            ans[pos] = 0;
            dfs(pos - 1, limit && (b[pos] == 0));
        }
    }
}

void solve(int r){
    pos = -1;
    while(r){
        ++ pos;
        b[pos] = (r & 1);
        r >>= 1;
    }
    dfs(pos, 1);
}

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    cin >> n >> q;
    for(int i = 1; i <= n; ++ i){
        cin >> op[i] >> num[i];
    }
    for(int i = 0; i < 30; ++ i){
        f[i][0] = calc(i, 0);
        f[i][1] = calc(i, 1);
    }
    while(q--){
        int r;
        cin >> r;
        solve(r);
        int val = 0;
        for(int i = 0; i <= pos; ++ i){
            if (ans[i])
                val |= (1 << i);
        }
        cout << val << '\n';
    }


    return 0;
}



L. Elden Ring (Nowcoder48876 L)

题目大意

\(2n\)个人, 各\(n\)个人围城一个环共两个环。从\(1\)\(n+1\)人从 \(1\)报数,报到\(m\)的倍数的两人交换位置。问报到\(k\)时的局面。

解题思路

\(k\)不大,按题意模拟即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    iota(a.begin(), a.end(), 1);
    iota(b.begin(), b.end(), n + 1);
    int m, k;
    cin >> m >> k;
    int pos = 0;
    int cnt = m;
    for(int i = 1; i <= k; ++ i){
        -- cnt;
        if (cnt == 0){
            swap(a[pos], b[pos]);
            cnt = m;
        }
        ++ pos;
        if (pos == n)
            pos = 0;
    }
    for(int i = 0; i < n; ++ i)
        cout << a[i] << ' ';
    for(int i = 0; i < n; ++ i)
        cout << b[i] << ' ';
    return 0;
}


posted @ 2022-12-10 21:48  ~Lanly~  阅读(177)  评论(0编辑  收藏  举报