zoukankan      html  css  js  c++  java
  • Codeforces Round #706 (Div. 2) A-D题解

    写在前边

    链接:Codeforces Round #706 (Div. 2)
    (A,B,C,D),这场有点简单,不过由于A写炸了后边题连看都没看就溜了,就从上大分变成了掉大分

    A. Split it!

    链接:A题链接

    题目大意:

    给定一个字符串(s),和一个数字(k),那么(a_i)(s)的一个子串,(R(a_i))代表(a_i)的逆序,问是否满足:

    [s = a_1 + a_2 + ... + a_k + a_{k + 1} + R(a_k) + R(a_{k - 1}) + ... + R(a_1) ]

    思路

    首先要知道,有一个单独的(a_{k + 1})部分,那么这部分,根本无所谓,但是对于它的两侧必然要是回文的,一开始就拽着回文串不放了,思维定势,以为全串必然要是回文才行,所以写炸了,所以只需要判断(s[1, k])是否等于(s[n - k + 1, n])(下标从1开始)即可,还要注意的是如果这个串的长度为偶数,那么(k)必然不能等于(cfrac{s.size()}{2})

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    #define pub push_back
    #define pob pop_back
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 10000007;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    void solve() {
        string s;
        int n, k;
        cin >> n >> k;
        cin >> s;
        if (k == 0) {
            puts("YES");
            return;
        }
    
        //这题并不一定要求中间是回文的
        if (s.size() % 2 == 0 && k == s.size() / 2) {
            puts("NO");
            return;
        }
        bool flag = true;
        for (int i = 0; i < k; i++) {
            if (s[i] != s[s.size() - 1 - i]) {
                flag = false;
                break;
            }
        }
        puts(flag ? "YES" : "NO");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
        return 0;
    }
    

    B. Max and Mex

    链接:B题链接

    题目大意:

    给定一个序列(s),我们可以进行(k)次操作,每次操作是添加一个(lceil cfrac{a + b}{2} ceil),(a = mex(s)), (b = max(s)),(max)就是序列中最大的数字,(mex)表示序列中最小不存在的非负整数,例如在序列(0,1,2,4)中,那么(mex = 3),问(k)次插入后,(S)中不同数字的个数有多少。

    思路

    先找到第一个(mex),如果(mex <= max(S)),可以发现,插入一个(lceil cfrac{a + b}{2} ceil),永远不会出现这个数,因此,mex就永远不会变化,与此同时插入的值也永远不会大于max,所以mex与max不变,那么序列中不同数的个数最多就加1,用一个set维护就好。
    如果(mex == max(S)),即假设序列为(0,1,2,3),那么第一个(mex)就是(4),所以(lceil cfrac{a + b}{2} ceil)算出来就是(mex),就插入一个新值,所以这种情况下,有多少个(k),就插入多少个新值。

    注意:取最大值的时候要看要注意数组并不一定是严格有序的啊!!

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <set>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    #define pub push_back
    #define pob pop_back
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    
    const int Mod = 10000007;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 1e5 + 10;
    int a[N];
    
    //题目没说给有序数组大哥
    void solve() {
        int n, k;
        scanf("%d%d", &n, &k);
        multiset<int> st2; //记录没有的数字 最小的数字
        set<int> st3;
    
        for (int i = 0; i < n; i++) scanf("%d", &a[i]);       
        
        sort(a, a + n);
        for (int i = 0; i < n; i++) {
            st3.insert(a[i]);
            st2.insert(a[i]);  
        }
    
        if (k == 0) {
            cout << st3.size() << endl;
            return;
        }
    
        int m = 0;
        for (auto &it : st2) {
            if (m != it) {
                break;
            }
            m++;
        }
    
        if (m > a[n - 1]) cout << n + k << endl;
        else {
            st3.insert((m + a[n - 1] + 1) / 2);
            cout << st3.size() << endl;
        }
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
    
        return 0;
    }
    

    C. Diamond Miner

    链接:C题链接

    题目大意:

    不说了,太简单了。

    思路

    排序,贪心求值就好了

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <cmath>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    #define pub push_back
    #define pob pop_back
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 10000007;
    
    const int N = 1e5 + 10;
    
    void solve() {
        int n;
        scanf("%d", &n);
        vector<int> a, b;
        for (int i = 0; i < n * 2; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            if (x == 0) b.push_back(abs(y));
            if (y == 0) a.push_back(abs(x));
        }
        
        sort(a.begin(), a.end());
        sort(b.begin(), b.end());
        
        double res = 0.0;
        for (int i = 0; i < n; i++) {
            res += sqrt((LL) a[i] * a[i] + (LL) b[i] * b[i]); //千万不要忘记long long
        }
        printf("%.15lf
    ", res);
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
    
        return 0;
    }
    

    D. Let's Go Hiking

    链接:D题链接

    题目大意:

    给题目大意转化一下就是,小(A)只能走一条单调递减序列,小(B)只能走一条单调递减序列,直到到某个人走的时候这个人无路可走了那么他就输了。题目中为小(A)先选一个起点,然后小B后选一个起点,接下来,小A先做决策,再B做决策,两者选择永远最优,问最后小A。

    思路

    是一道博弈论的题目,两个人都是在单调的路上走,并且对于(B)来说,肯定要想办法让A输,A肯定想找一条最长的路走,所以有下面几种情况:
    如果两个以上的单调段,那么先手必然输,因为:

    1. 如果是全是一个方向的单调段,那么小(A)无论如何都会被小(B)堵截。
    2. 如果对于山峰段,即一个点左右分别为单调递增单调递减,有多个,那么(B)后手总能选到一个地方赢得比赛(画几个例子试试)。
    3. 如果对于山谷段,及一个点左右分别为单调递减单调递增,有多个,那么(B)后手也同样总能选到一个地方赢得比赛(画几个例子试试)。

    如果就只有一个单调段,那么更不用说了,B只需要放在A旁边堵A即可,赢得比赛。

    所以如果想要先手赢,那么必然是只要一个山峰段,同时山峰段还要左右恰好对称才可以,如果不对称那(B)也可以找一个地方拦截(A),或者走的路比更长,如果对称情况下,(A)必然选择连接点,而这时小(B)只能选两端点,这时如果(A)躲避(B)走另一边,那么它无论如何都输,因此他只能跟(B)对着走,而这时如果(maxl % 2 == 0),那么它依然输,所以只有(maxl % 2 != 0)情况下同时是对称的山峰段才赢,其余情况均输。

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    #define pub push_back
    #define pob pop_back
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 1000000007;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 1E5 + 10;
    int n, p[N];
    int pre[N], suff[N];
    
    void solve() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
    
        for (int i = 1; i <= n; i++) {
            if (p[i] > p[i - 1]) pre[i] = pre[i - 1] + 1;
            else pre[i] = 1;
        }
        for (int i = n; i >= 1; i--) {
            if (p[i] > p[i + 1]) suff[i] = suff[i + 1] + 1;
            else suff[i] = 1;
        }
    
        /* for (int i = 1; i <= n; i++) cout << pre[i] << " ";
        cout << endl;
        for (int i = 1; i <= n; i++) cout << suff[i] << " ";
        cout << endl; */
    
        int maxl = 0;
        for (int i = 1; i <= n; i++) maxl = max({maxl, pre[i], suff[i]});
    
        int cnt1 = 0, cnt2 = 0, idx1 = 0, idx2 = 0;
        for (int i = 1; i <= n; i++) {
            if (pre[i] == maxl) {
                cnt1++;
                idx1 = i;
            }
            if (suff[i] == maxl) {
                cnt2++;
                idx2 = i;
            }
        }
    
        if (cnt1 + cnt2 != 2) {
            puts("0");
            return;
        } else if (cnt1 + cnt2 == 2 && idx1 == idx2) {   
            puts(maxl % 2 == 0 ? "0" : "1");
        } else puts("0");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        solve();
        return 0;
    }
    
  • 相关阅读:
    2020-2021-1 20201314 《信息安全专业导论》第三周学习总结
    罗马数字转阿拉伯数字
    BASE64编码-20201314黄斯阳
    学期(2020-2021-1) 学号(20201314) 《信息安全专业导论》第2周学习总结
    师生关系
    快速浏览教材 。
    浏览教材的疑问
    2020-2021-1 20201314 《信息安全专业导论》第一周学习总结
    第四周作业补交
    第四周作业
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/14528906.html
Copyright © 2011-2022 走看看