欢乐结训赛题解

欢乐结训赛题解

A 题目链接

  • 题目大意
给你一个字符串,让你求字符串中最大的字母在字母表中排第几 例如 codeforces 中 s 的是最大的 s在字母表中排 19位
  • 代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 10;
    const int mod = 1e9 + 7;
    void solve()
    {
        string s;
        int n;
        cin >> n;
        cin >> s;
        int maxx = 0;
        for (int i = 0; i < s.length(); i++)
        {
            maxx = max((int)s[i], maxx);
        }
        cout << maxx - 'a' + 1 << '\n';
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int __ = 1;
        cin >> __;
        while (__--)
        {
            solve();
        }
        return 0;
    }
    

B 题目链接

  • 题目大意

    给你一个数组a,对于每个a[i],在a数组中找出除了a[i]自己,最大的数,然后输出该数与a[i]的差值 
    
  • 思路

    求出数组中最大的数(maxx_1)和第二大的数(maxx_2),遍历数组,如果a[i]不是最大的数 就输出a[i]-maxx_1,否则输出a[i]-maxx_2
    
  • 代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 10;
    const int mod = 1e9 + 7;
    void solve()
    {
        int n;
        cin >> n;
        vector<int> vec(n);
        int maxx = 0;
        int sec = 0;
        for (int i = 0; i < n; i++)
        {
            cin >> vec[i];
            if (vec[i] > maxx)
            {
                sec = maxx;
                maxx = max(vec[i], maxx);
            }
            else if (vec[i] > sec)
            {
                sec = vec[i];
            }
        }
        for (int i = 0; i < n; i++)
        {
            if (vec[i] != maxx)
            {
                cout << vec[i] - maxx << ' ';
            }
            else
            {
                cout << maxx - sec << ' ';
            }
        }
        cout << '\n';
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int __ = 1;
        cin >> __;
        while (__--)
        {
            solve();
        }
        return 0;
    }
    

C题目链接

  • 题目大意

    给定一串数组,问这个数组a[ l .....r ]是否满足如下性质
    0 <= l <= r <= n - 1
    a l = a l + 1 = a l + 2...... = ar
    l = 0 or a l - 1 > a l
    r = n - 1 or a r < a r + 1
    若满足这些性质,输出YES 否则输出 NO
    
  • 思路

    形成一个山谷我们需要先下降然后上升
    我们定义一个flag 
    flag=0 代表 现在是无状态
    flag=1 代表 下降状态,如果接下来有一个上升的话就会形成一个山谷
    需要注意 初始时 flag为1,结束时还需要判断一下flag是否为1 如果为1,山谷数+1 原因见原题目
    具体实现见代码
    
  • 代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 10;
    const int mod = 1e9 + 7;
    void solve()
    {
        int n;
        cin >> n;
        vector<int> vec(n);
        for (int i = 0; i < n; i++)
            cin >> vec[i];
        int flag = 1;
        int cnt = 0;
        for (int i = 1; i < n; i++)
        {
            if (vec[i] > vec[i - 1])  //假如现在是上升 并且flag状态为1 ,山谷数+1
            {
                if (flag == 1)
                {
                    flag = 0;
                    cnt++;
                }
            }
            else if (vec[i] < vec[i - 1]) //如果现在是下降 那么将flag赋值为1
            {
                flag = 1;
            }
        }
        if (flag == 1)
            cnt++;
        if (cnt == 1)
            cout << "YES\n";
        else
            cout << "NO\n";
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int __ = 1;
        cin >> __;
        while (__--)
        {
            solve();
        }
        return 0;
    }
    

D 题目链接

  • 题目大意

    给定一串二进制数组,把其中一个 1 变成 0 或者 0 变成 1 使得数组逆序对数量最大,问这个最大数量是几
    
  • 思路

    先求出不变的情况下 逆序对的个数 ans
    case1:我们把一个0 变成1 那么这次改变对答案的贡献为 后面所有的0 - 前面所有的1 
    case2:我们把一个1 变成0 那么这次改变对答案的贡献为 前面所有的1 - 后面所有的0
    然后把所有的情况都算出来 得到一个最大值 加到ans上 详情见代码 时间复杂度(O(n))
    
  • 代码

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 2e5 + 10;
    const int mod = 1e9 + 7;
    int sum[N];  //sum[i] 代表前i个数有多少个1
    void solve()
    {
        int n;
        cin >> n;
        vector<int> vec(n + 1);
        for (int i = 1; i <= n; i++)
        {
            sum[i] = 0;
        }
        for (int i = 1; i <= n; i++)
        {
            cin >> vec[i];
            sum[i] = sum[i - 1] + vec[i];
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)  //先计算 不变的情况下的答案
        {
            if (vec[i] == 1)
            {
                ans += ((n - i) - (sum[n] - sum[i]));
            }
        }
        int maxx = 0;
        for (int i = 1; i <= n; i++)
        {
            if (vec[i] == 0)
            {
                maxx = max(maxx, ((n - i) - (sum[n] - sum[i])) - sum[i]); //逻辑 见思路
            }
            else if (vec[i] == 1)
            {
                maxx = max(maxx, sum[i - 1] - ((n - i) - (sum[n] - sum[i]))); //逻辑 见思路 
            }
        }
        cout << maxx + ans << '\n';
    }
    signed main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int __ = 1;
        cin >> __;
        while (__--)
        {
            solve();
        }
        return 0;
    }
    

E 题目链接

  • 题目大意

    有n个任务。如果你完成第i个任务,你将获得ai币。你每天最多只能完成一个任务。然而,一旦你完成了一个任务,在K天内你不能再做同样的任务。(例如,如果k=2,你在第1天做了任务1,那么你在第2天或第3天不能做,但你可以在第4天再做)。
    给你两个整数c和d。找出k的最大值,使你在d天内至少能获得c个硬币。如果不存在这样的k,则输出Impossible。如果k可以是任意大的,则输出Infinity。
    
  • 思路

    二分答案
    得到数组后先排序 
    如果最大的a[i]*d < c的话 那么无解 输出 Impossible
    如果排序后数组的 前d 个数的和 > c 输出 Infinity
    
    然后进行二分答案 具体的check函数 见代码 
    需要注意的是 代码中min函数对数组访问越界的控制 
    
  • 代码

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 2e5 + 10;
    const int mod = 1e9 + 7;
    int vec[N];
    int c, d;
    int n;
    bool check(int k)
    {
        k += 1;
        int sy = d - (d / k) * k;  //进行k轮后剩余的天数 等效于 sy = d % k 也可以
        int js = 0;
        for (int i = 1; i <= min(k, n); i++)
        {
            js += vec[i];
        }
        js *= (d / k);
        for (int i = 1; i <= min(sy, n); i++)
        {
            js += vec[i];
        }
        return js >= c;
    }
    void solve()
    {
        cin >> n >> c >> d;
        for (int i = 1; i <= n; i++)
        {
            cin >> vec[i];
        }
        sort(vec + 1, vec + n + 1, greater<int>());
        if (vec[1] * d < c)
        {
            cout << "Impossible" << '\n';
            return;
        }
        else
        {
            int ans = 0;
            for (int i = 1; i <= min(n, d); i++)  //不能直接 i<=d 因为d可能比n大 导致访问越界 其他地方的min函数作用亦然
            {
                ans += vec[i];
            }
            if (ans >= c)
            {
                cout << "Infinity" << '\n';
                return;
            }
            else
            {
                int anss = 0;
                int l = 0, r = 1e9 + 10;
                while (l <= r)
                {
                    int mid = l + r >> 1;
                    if (check(mid))
                    {
                        anss = mid;
                        l = mid + 1;
                    }
                    else
                    {
                        r = mid - 1;
                    }
                }
                cout << anss << '\n';
            }
        }
    }
    signed main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int __ = 1;
        cin >> __;
        while (__--)
        {
            solve();
        }
        return 0;
    }
    

F题目链接

  • 题目大意

     给你一棵树和两个点α,b,边有边权。你可以在任意时刻从当前所在的点跳到任意除了b以外的点。求有没有方案使得从a出发,到达b时边权X0r和为0。
    
  • 思路

    首先我们确定一个共识 就是一条边不会被走两次 因为重走一条边没有任何意义 x^x=0 并且这是一棵树 是不会出现环的
    我们考虑先从b出发做一遍 bfs 在bfs的过程中 我们可以得到很多的 {x,y} x代表当前走到的点 y代表走到这个点的val
    我们定义一个 map<int> mp 对于每一个{x,y} 我们让 mp[y]=1;
    
    我们再考虑从a点出发 做一遍bfs 我们会获得很多的 {x1,y1} x1代表当前走到的点 y1代表走到这个点的val。如果mp[y1]=1的话,我们就可以直接飞到一个点 使得最后走到b的异或和为0; 
    
  • 代码

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 1e5 + 10;
    const int mod = 1e9 + 7;
    vector<pair<int, int>> vec[N];
    int vis[N];
    void solve()
    {
        map<int, int> mp;
        int n;
        int a, b;
        cin >> n >> a >> b;
        for (int i = 1; i <= n; i++)
        {
            vis[i] = 0;
            vec[i].clear();
        }
        for (int i = 1; i <= n - 1; i++)
        {
            int u, v, val;
            cin >> u >> v >> val;
            vec[u].push_back({v, val});
            vec[v].push_back({u, val});
        }
        queue<pair<int, int>> que;
        que.push({b, 0});
        vis[b] = 1;
        while (que.size())
        {
            auto u = que.front();
            que.pop();
            if (u.first != b)
                mp[u.second] = 1;
            for (int i = 0; i < vec[u.first].size(); i++)
            {
                if (!vis[vec[u.first][i].first])
                {
                    vis[vec[u.first][i].first] = 1;
                    que.push({vec[u.first][i].first,
                              vec[u.first][i].second ^ u.second});
                }
            }
        }
        for (int i = 1; i <= n; i++)
            vis[i] = 0;
        que.push({a, 0});
        vis[a] = 1;
        vis[b] = 1;
        int flag = 0;
        while (que.size())
        {
            auto u = que.front();
            if (mp[u.second])
            {
                flag = 1;
                break;
            }
            que.pop();
            for (int i = 0; i < vec[u.first].size(); i++)
            {
                if (!vis[vec[u.first][i].first])
                {
                    vis[vec[u.first][i].first] = 1;
                    que.push({vec[u.first][i].first,
                              vec[u.first][i].second ^ u.second});
                }
            }
        };
        if (flag == 1)
            cout << "YES\n";
        else
            cout << "NO\n";
    }
    signed main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int __ = 1;
        cin >> __;
        while (__--)
        {
            solve();
        }
        return 0;
    }
    

G 题目链接

G题纯签到就不讲了。

题解写的有错误还请指正。

posted @ 2023-05-29 20:50  x1uc  阅读(52)  评论(0)    收藏  举报