ZZJC新生训练赛第十场题解

先给出比赛链接:
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

这是一题构造,由于 bi=ai&ai+1 , 所以 bi1aiai+11

构造完检查一遍是否符合即可

异或及其性质

异或在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=k=01i=1na[k][i]+i=1nsa[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整除。
要检查第一个条件,检查所有可能的 p2 即可(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";
        }
    }
}




posted @   Proaes  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示