首页 > 其他分享 >ZZJC新生训练赛第十场题解

ZZJC新生训练赛第十场题解

时间:2024-10-27 20:20:15浏览次数:1  
标签:ZZJC 新生训练 int 题解 tt cin -- vector cur

先给出比赛链接:
https://vjudge.net/contest/667035

下面说一下难度分层:(同一难度下按字典序排序,数字为cf难度分)
800: A B E G

1100: D

1200: C

1400: H

1500: F

原题链接

A : https://codeforces.com/contest/1850/problem/A
B : https://codeforces.com/contest/1991/problem/A
C : https://codeforces.com/problemset/problem/1996/C
D : https://codeforces.com/contest/1991/problem/B
E : https://codeforces.com/contest/2008/problem/C
F : https://codeforces.com/contest/1990/problem/C
G : https://codeforces.com/problemset/problem/1598/A
H : https://codeforces.com/contest/679/problem/A

A To My Critics

把最大的两个加起来判断是否大于10即可

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    int tt = 1;
    cin >> tt;
    while (tt--) {
        int n = 3;
        vector<int> a(n + 1);
        for (int i = 1; i <= n; ++ i) cin >> a[i];
        sort(a.rbegin(), a.rend() - 1);
        if (a[1] + a[2] >= 10) {
            cout << "YES\n";
        } else {
            cout << "NO\n";
        }
    }
}




B Maximize the Last Element

由于每次删的是两个连续的,所以最后剩下的只可能是原数组奇数位上的数,取一下max即可

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    int tt = 1;
    cin >> tt;
    while (tt--) {
        int n, ans = 0;
        cin >> n;
        vector<int> a(n + 1);
        for (int i = 1; i <= n; ++ i) cin >> a[i];
        for (int i = 1; i <= n; ++ i) {
            if (i & 1) {
                ans = max(ans , a[i]);
            }
        }
        cout << ans << "\n";
    }
}




C Sort

观察可得,对于每个区间的查询,答案就是两个字符串每种字符数量的差值之和的一半,前缀和维护一下即可

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    auto prefix = [&](vector<ll> &a , int lena) {
        vector<ll> sa(lena + 1);
        for (int i = 1; i <= lena; ++ i) {
            sa[i] = sa[i - 1] + a[i];
        }
        return sa;
    };
    auto get = [&](vector<ll> &sa , int xb , int xe) {
        ll res = sa[xe] - sa[xb - 1];
        return res;
    };

    int tt = 1;
    cin >> tt;
    while (tt--) {
        int n, q;
        cin >> n >> q;
        string s1, s2;
        cin >> s1 >> s2;
        vector<vector<ll>> a1(27, vector<ll>(n + 1));
        vector<vector<ll>> a2(27, vector<ll>(n + 1));
        for (int i = 1; i <= n; ++ i) {
            int c1 = s1[i - 1] - 'a';
            a1[c1][i]++;
            int c2 = s2[i - 1] - 'a';
            a2[c2][i]++;
        }
        vector<vector<ll>> sa1(27, vector<ll>(n + 1));
        vector<vector<ll>> sa2(27, vector<ll>(n + 1));
        for (int i = 0; i < 26; ++ i) {
            sa1[i] = prefix(a1[i], n);
            sa2[i] = prefix(a2[i], n);
        }
        while (q--) {
            int l , r;
            cin >> l >> r;
            int d = 0;
            for (int i = 0; i < 26; ++ i) {
                d += abs(get(sa1[i], l, r) - get(sa2[i], l, r));
            }
            int ans = d / 2;
            cout << ans << "\n";
        }
    }
}




D AND Reconstruction

这是一题构造,由于 $ b_{i} = a_{i} & a_{i + 1} $, 所以 $ 当b_{i} 的某一位为1时 a_{i} 和 a_{i + 1} 这一位上肯定是1 $
构造完检查一遍是否符合即可

异或及其性质

异或在C++中的运算符是 ^ 
异或可以理解为按位不进位加法
1.异或的逆运算就是异或本身 如果 a ^ b = c ,那么 c ^ b = a 

2.异或满足交换律 即 a ^ b == b ^ a
3.异或满足结合律 即 (a ^ b) ^ c == a ^ (b ^ c)
4.异或满足分配律 即 a ^ (b & c) == (a ^ b) & (a ^ c)
对于普通加法可以用高斯定律 sn = (1 + n) * n / 2 快速计算1~n的值 对于异或运算来说也有快速计算1~n各数的异或和的方法,即:
s(n)为1到n的数的异或和 s(n) = 1 , n % 4 == 1 s(n) = 0 , n % 4 == 3 s(n) = n , n % 4 == 0 s(n) = n + 1 , n % 4 == 2
代码实现如下: auto xorprefix = [&](ll n) { int flag = n % 4; if (flag == 0) { return n; } else if (flag == 1) { return 1; } else if (flag == 2) { return n + 1; } else if (flag == 3) { return 0; } };
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    int tt = 1;
    cin >> tt;
    while (tt--) {
        int n;
        cin >> n;
        vector<ll> a(n + 1);
        vector<vector<ll>> ab(n + 1 , vector<ll>(32));
        vector<ll> b(n + 1);
        for (int i = 1; i < n; ++ i) cin >> b[i];
        for (int i = 1; i < n; ++ i) {
            ll cur = b[i];
            int len = 0;
            while (cur) {
                if (cur % 2 == 1) {
                    ab[i][len] = 1;
                    ab[i + 1][len] = 1;
                }
                cur /= 2;
                len++;
            }
        }
        for (int i = 1; i <= n; ++ i) {
            ll cur = 0;
            for (int j = 30; j >= 0; -- j) {
                cur = cur * 2ll + ab[i][j];
            }
            a[i] = cur;
        }
        for (int i = 1; i < n; ++ i) {
            if ( (a[i] & a[i + 1]) != b[i]) {
                flag = 0;
            }
        }
        bool flag = 1;
        if (flag) {
            for (int i = 1; i <= n; ++ i) {
                cout << a[i] << " \n"[i == n];
            } 
        } else {
            cout << -1 << "\n";
        }
    }
}




E Longest Good Array

贪心一下,公差的公差肯定是1,那么先生成这个数组(初始值为0,公差的公差为1),然后计算出区间的长度d,二分找到数组内第一个小于等于d的值即可

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    vector<ll> dp(100005);
    for (int i = 2; i <= 100000; ++ i) {
        dp[i] = dp[i - 1] + i - 1;
    }

    int tt = 1;
    cin >> tt;
    while (tt--) {
        ll l, r;
        cin >> l >> r;
        ll d = r - l;
        int pos = (--upper_bound(dp.begin(), dp.end(), d)) - dp.begin(); // 二分查找,返回数组中第一个小于于等于d的位置
        cout << pos << "\n";
    }
}




F Mad MAD Sum

经过一次运算后,数组变得不递减。

再经过一次运算后,数组变得往后移动。

设 \(a[k]\) 为 \(a\) 数组经过 \(k\) 次操作以后的数组, \(sa[k]\) 为 \(a\) 数组经过 \(k\) 次操作以后的数组的前缀和数组

所以 $ sum = \sum\limits_{k = 0}^{1} \sum\limits_{i = 1}^{n} a[k][i] + \sum\limits_{i = 1}^{n} sa[2][i] $

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    // 一维前缀和
    auto prefix = [&](vector<ll> &a , int lena) {
        vector<ll> sa(lena + 1);
        for (int i = 1; i <= lena; ++ i) {
            sa[i] = sa[i - 1] + a[i];
        }
        return sa;
    };

    int tt = 1;
    cin >> tt;
    while (tt--) {
        bool flag = 0;
        ll n, sum = 0, cur = 0;
        cin >> n;
        vector<vector<ll>> a(3, vector<ll>(n + 1));
        for (int i = 1; i <= n; ++ i) {
            cin >> a[0][i];
            sum += a[0][i];
        }
        auto f = [&](int k) {
            cur = 0;
            map<ll, ll> mp;
            for (int i = 1; i <= n; ++ i) {
                mp[a[k - 1][i]] ++;
                if (mp[a[k - 1][i]] > 1) cur = max(cur , a[k - 1][i]);
                a[k][i] = cur;
                if (k == 1) sum += a[k][i];
            }
        };
        f(1);
        f(2);
        vector<ll> sa2 = prefix(a[2], n);
        for (int i = 1; i <= n; ++ i) sum += sa2[i];
        cout << sum << "\n";
    }
}




G Computer Game

这题可以用DP或者dfs解决

设 \(dp[i][j] = 1\) 表示该点能到达,然后先列再行遍历转移状态,最后判断 \(dp[2][n]\) 是否为 \(1\) 即可

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    int tt = 1;
    cin >> tt;
    while (tt--) {
        int n;
        cin >> n;
        vector<string> s(3);
        vector<vector<int>> dp(4, vector<int>(n + 1));
        cin >> s[1] >> s[2];
        s[1] = " " + s[1];
        s[2] = " " + s[2];
        dp[1][1] = 1;
        for (int j = 1; j <= n; ++ j) {
            for (int i = 1; i <= 2; ++ i) {
                if (s[i][j] == '0' && (i != 1 || j != 1)) {
                    if (dp[i - 1][j] == 1) dp[i][j] = 1;
                    if (dp[i - 1][j - 1] == 1) dp[i][j] = 1;
                    if (dp[i][j - 1] == 1) dp[i][j] = 1;
                    if (dp[i + 1][j - 1] == 1) dp[i][j] = 1;
                    if (dp[i + 1][j] == 1) dp[i][j] = 1;
                }
            }
        }
        if (dp[2][n]) {
            cout << "YES\n";
        } else {
            cout << "NO\n";
        }
    }
}




H Bear and Prime 100

如果一个数是合数,那么它要么能被某个素数p整除,要么能被两个不同的素数p和q整除。
要检查第一个条件,检查所有可能的 \(p^{2}\) 即可(4, 9, 25, 49), 如果至少有一个yes,那么隐藏数为合数

如果有两个不同的素因子p和q,那么它们都不超过50,否则隐藏数将大于100(因为对于p≥ 2和q> 50,我们将得到p·q> 100)。所以,检查最多50个素数(有15个),并检查其中是否至少有两个是除数就足够了。

constexpr int maxn = 1e3; 
int pnl[maxn + 10], cnt;//pnl
bool st[maxn + 10]; //索引为质数值就是0
void init_primes() {
    st[0]=1;
    st[1]=1;
    for (int i=2; i <= maxn; ++i) {
        if (st[i] == 0) { pnl[cnt++] = i; }
        for (int j=0; pnl[j] <= maxn / i; ++j){
            st[pnl[j]*i] = 1;
            if (i%pnl[j] == 0) { break; }
        }
    }
}

int main() {

    init_primes();

    int tt = 1;
    // cin >> tt;
    while (tt--) {
        auto query = [&](int cur) {
            cout << cur << endl;
            cur ++;
            string s;
            cin >> s;
            return s;
        };
        bool flag1, flag2;
        int cnt = 0;
        int n = 4;
        for (int i = 0; i < 15; ++ i) {
            if (query(pnl[i]) == "yes") {
                cnt++;
            }
        }
        if (cnt <= 1) {
            flag1 = 1;
        } else {
            flag1 = 0;
        }
        cnt = 0;
        for (int i = 0; i < 4; ++ i) {
            if (query(pnl[i] * pnl[i]) == "yes") {
                cnt++;
            }
        }
        if (cnt >= 1) {
            flag2 = 0;
        } else {
            flag2 = 1;
        }
        if (flag1 & flag2) {
            cout << "prime\n";
        } else {
            cout << "composite\n";
        }
    }
}




标签:ZZJC,新生训练,int,题解,tt,cin,--,vector,cur
From: https://www.cnblogs.com/Proaes/p/18508879

相关文章

  • Codeforces Round 981 (Div. 3) 题解(A-E)
    目录分析A思路代码B思路卡题原因代码C思路卡题原因codeD思路卡题原因代码E思路wa原因codeCodeforcesRound981(Div.3)分析这场整体发挥都不好,虽然题也抽象,但是对于这些题完全没必要卡这么久.正常至少能看到\(\mathbf{F}\)A思路因为边界\(n\)管辖\(\pm\),而Sak......
  • P11234 [CSP-S 2024] 擂台游戏 题解
    P11234[CSP-S2024]擂台游戏题解前言作者在考场上用了约1h把前三道题做完了,然后用了约半小时想了带\(\log\)的做法,但是我决定放手一搏去想线性的做法,于是又想了有1h之后觉得想到了正解,然后我就一直写到了考试结束,但是最终没有调出来遗憾离场,因此写个题解来纪念一下。......
  • Codeforces Round 980 (Div. 2) 题解(A-D)
    目录A思路B思路wa原因C思路wa原因代码D思路未ac原因代码CodeforcesRound980(Div.2)A思路推方程式即可,勉强算贪心吧.需要使得\({a-x}\)最小,那么\(x\)就需要最小,而满足题目条件,需要\(a-x\geb-2x\)得出\(x\geb-a\),又因为需要\(a\)最大,所以\(......
  • 题解:P2013 无线电测向
    P2013无线电测向题目省流:求两条直线交点坐标使用样例数据作出下图:(图片来自@_MRCMRC_)图中红线和紫线为灯塔与船的连线,蓝线为船的航线。由输入可以知道灯塔A、B相对于\(x\)正半轴的角度\(\theta_A\)、\(\theta_B\)(逆时针方向)和它们分别的坐标\((x_A,y_A)\)、\((x_B,......
  • DYN / 消防局的设立 / Spread of Information / 将军令 题解
    前言四倍经验:[POI2011]DYN-Dynamite;[HNOI2003]消防局的设立;[ARC116E]SpreadofInformation;将军令。题意简述给你一棵\(n\)个结点的树和点集\(S\),你要选出\(k\)个关键点\(T\),求\(\min\max\limits_{u\inS}\min\limits_{v\inT}\operatorname{dis}(u,v)\)......
  • CSP-J 2024 复赛题解
    T1数据仅有52,极小的数据范围导致这题只有一个问题:如何简短方便的去重并统计。我选择了map做法:每个输入查找map中之前是否记录过此元素,如果记录过则证明已经拥有这张牌,反之则记录并将统计数增加。代码如下:#include<bits/stdc++.h>usingnamespacestd;intn;map<stri......
  • Stema练习题:十四届蓝桥杯STEMA考试Python真题试卷题解
    来源:十四届蓝桥杯STEMA考试Python真题试卷第一套编程第四题这个程序虽然代码量不大,但综合运用了多种基础算法和数据结构:贪心策略选择窗口、模拟现实过程、线性查找最小值、效率高(时间复杂度为O(N)O(N)O(N))。题目描述:编程实现:某服务大厅同时开放3个窗口为客户办理......
  • Codeforces Round 982 div2 个人题解(A~D2)
    CodeforcesRound982div2个人题解(A~D2)Dashboard-CodeforcesRound982(Div.2)-Codeforces火车头#define_CRT_SECURE_NO_WARNINGS1#include<algorithm>#include<array>#include<bitset>#include<cmath>#include<cstdio>#in......
  • CF102354B Yet Another Convolution 题解
    题目描述给定长为\(n\)的数列\(a,b\),求数列\(c\)满足:\[c_k=\max_{\gcd(i,j)=k}|a_i-b_j|\\\]数据范围\(1\len\le10^5,1\lea_i,b_i\le10^9\)。时间限制\(\texttt{6s}\),空间限制\(\texttt{256MB}\)。分析别被题目名字带偏了,这道题跟卷积没有一点关系。如果......
  • 洛谷 P5738 【深基7.例4】歌唱比赛 C语言 题解
    题目描述n(n≤100)n(n≤100) 名同学参加歌唱比赛,并接受 m(m≤20)m(m≤20) 名评委的评分,评分范围是 00 到 1010 分。这名同学的得分就是这些评委给分中去掉一个最高分,去掉一个最低分,剩下 m−2m−2 个评分的平均数。请问得分最高的同学分数是多少?评分保留 22 位小数......