Codeforces Round 910 (Div. 2)A-D

比赛传送门

心得:最近感觉运气好了不少,思路挺正确的,开完ABD就摆了,结果最后几分钟才开始写,还是差点,后面才改过,别摆了,学会儿吧,hhh。这篇题解也是我第一次写下的CF题解(没有借鉴别人的),如有不对,请多海涵。

A. Milica and String

tag:签到

思路:

先看初始状态有多少个B,因为这题是直接覆盖,所以就简单了。刚好就直接输出,多了就减少,少了就增加。假设初始状态有res个B,从头开始遍历。

(1)多了的情况下:遇到B就res--,如果res == k了,就直接输出i+1

(2)少了的情况下:遇到B就res++,如果res == k了,就直接输出i+1

// 加油昂!!!
// Problem: A. Milica and String
// Contest: Codeforces - Codeforces Round 910 (Div. 2)
// URL: https://codeforces.com/contest/1898/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include 
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<> n >> m;
    string s;
    cin >> s;
    int res = count(s.begin(), s.end(), 'B');
    if (res == m)
    {
        cout <<"0\n";
        return;
    }
    cout << "1\n";
    if (res < m)
    {
        for (int i = 0; i < n; i++)
        {
            if (s[i] == 'A') res++;
            if (res == m)
            {
                cout << i + 1 << " B\n";
                return;
            }
        }
    }
    else
    {
        for (int i = 0; i < n; i++)
        {
            if (s[i] == 'B') res--;
            if (res == m)
            {
                cout << i + 1 << " A\n";
                return ;
            }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int ___ = 1;
    cin >> ___;
    while (___--)
        solve();
    return 0;
}

B. Milena and Admirer

tag:思维,贪心

思路:

先贪心的想,从前往后不太好搞,比如样例:6 3 2,你根据3把6操作了,变成3 3 3 2,但是2没满足,又要把前面3个3重新分开,就很麻烦(太懒了,懒得想这个了),于是换种思路,从后往前操作,那么按照题意模拟我们是不是每次从a[i-1]中取出来一个a[i](如果能够取出来的话),那么我们能取出来的个数就是前一个数除后一个数并上取整再-1,又因为他一次操作能得到两个数字,所以我们往答案中加的时候就需要减去一个1,但是我们改变之后本来属于a[i-1]的位置变成了多个数字,我们总有办法让这些数字内部进行非递减排序,那么这些数字最前面的那个数字和a[i-2]的大小关系呢,我们还是通过一个样例观察:2 9 4,如果从9中贪心的减去4,最后得到的是2 (1 4 4) 4,那么这样就需要再操作一下第一个数字,答案就是1 + 2,但是如果我们让分出来的两个4分一点数字给1,那么我们就可以得到2 (3 3 3) 4,这样就满足条件了且只需要2次,所以我们得出结论找出最少分裂的次数,并使最小的数字最大即可。

// 加油昂!!!
// Problem: B. Milena and Admirer
// Contest: Codeforces - Codeforces Round 910 (Div. 2)
// URL: https://codeforces.com/contest/1898/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include 
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<> n;
    vector a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    int ans = 0;
    for (int i = n - 1; i > 0; i--)
    {
        if (a[i] < a[i - 1])
        {
            int res = (a[i - 1] + a[i] - 1) / a[i];
            ans += (res - 1);
            a[i - 1] /= res; 
        }
    }
    cout << ans << "\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int ___ = 1;
    cin >> ___;
    while (___--)
        solve();
    return 0;
}

C. Colorful Grid

tag:构造,思维

思路:

手推完样例即可发现:最短路径是n-1+m-1,然后其余的路径必定是最短路径加上2*k(k为非负数)不能走到终点,或者其余的步数不是2的倍数,那么就是NO;然后又因为走4步可以回到原位置,所以我们可以把2*k里面的4全部拿去绕圈圈即可(图中右下角蓝色部分),那么就需要判断是否还有2步的存在。首先我们假设先往下走,再往右走(如图箭头所指),如果还绕弯圈圈之后还剩下2步,那么我们就把他安排在图中左上角开始出发的位置进行绕路操作,如图这样就能实现多走两步的操作,路线确定完毕之后我们就需要给出路径上路径的颜色了,我们先安排竖着的路径分别为R,B,R,B,R,B……,那么在安排横着这条路径的时候我们就应该从竖着的结束的那一个开始继续编号,然后其他的不是路径的边就和他的左边或者下面的边颜色一样即可。这样就把走(1)最短路径和(2)最短路径加绕圈 的情况处理完毕。(往下翻一点)

Codeforces Round 910 (Div. 2)A-D_第1张图片

 绕路的时候可以存在颜色会不满足的情况,(这里的n为偶数,所以有奇数条边)比如这里的第三步和第四步颜色一样,我们就需要把前三步的颜色翻转一下即可。

 Codeforces Round 910 (Div. 2)A-D_第2张图片

(n为奇数,所以有偶数条边)的情况, 第1,2,3步相同,那么我们就只需要把第二步改成相反颜色即可。(我wa2的那一发就是把这个情况和上面那种情况混为一谈了)。

Codeforces Round 910 (Div. 2)A-D_第3张图片

如果%4余2的话,就需要特判这两种情况,至此,该问题得以解决。

// 加油昂!!!
// Problem: C. Colorful Grid
// Contest: Codeforces - Codeforces Round 910 (Div. 2)
// URL: https://codeforces.com/contest/1898/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include 
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<> n >> m >> k;
    if (k < n - 1 + m - 1 || (k - n - m + 2) % 2 == 1) NO
    cout << "YES\n";
    int ans = (k - n - m + 2);
    int x2 = (ans % 4 > 0);
    for (int i = 0; i < n - 1; i++) //竖着的路径
    {
        for (int j = 0; j < m; j++)
        {
            pm[i][j] = p[i % 2];
            if (x2 && i == 0 && j <= 1) pm[i][j] = p[(i + 1) % 2];
            //改变绕路的边颜色
        }
    }
    if (n % 2 == 0) swap(p[0], p[1]);
    for (int i = 0; i < n; i++) //横着的路径
    {
        for (int j = 0; j < m - 1; j++) 
        {
            pn[i][j] = p[j % 2];
            if (x2 && i <= 1 && j == 0 && n % 2 == 0) pn[i][j] = p[(j + 1) % 2]; 、
            //如果n为奇数就不需要改变横着的绕路的边
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m - 1; j++)
        {
            cout << pn[i][j] <<  " \n"[j == m - 2];
        }
    }
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cout << pm[i][j] << " \n"[j == m - 1];
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int ___ = 1;
    cin >> ___;
    while (___--)
        solve();
    return 0;
}

D. Absolute Beauty

tag:思维

思路:

枚举一下两对元素的大小关系假设a1,b1,a2,b2;那么把他们看成线段,就有有交叉和无交叉的两种,再细分在交叉的情况下,有以下四种情况,第一种和第四种情况交换后对答案不会产生影响,第二种和第三种情况交换后会让答案少去重合的那部分,会减少,也不可取;

Codeforces Round 910 (Div. 2)A-D_第4张图片

再看无交叉的情况如下,我们假设上面那一段为l1,下面那一段为l2,中间空缺为m,初始状态都是贡献都是:l1+l2。交换后:(上a和下b,下a和上b)

(1)l1+l2+m 和 m ,得到:l1+l2+m*2

(2)l1+m 和 l2+m ,得到:l1+l2+m*2

(3)l2+m 和 l1+m ,  得到:l1+l2+m*2

(4)m 和 l1+l2+m , 得到:l1+l2+m*2

那么他们对答案的贡献都是中间这一段的两倍,我们就需要求出一个最大的m即可,所以我们对于每一个数对,设置一个最大值和最小值,假设我们取答案的时候,对于在上面的数对ab,我们肯定找目前最大值最小的数对ab;对于在下面的数对ab,找目前最小值最大的数对ab。这样就能让m的值最大化,然后再加上累加求和abs(ai -bi)即可。

Codeforces Round 910 (Div. 2)A-D_第5张图片

// 加油昂!!!
// Problem: D. Absolute Beauty
// Contest: Codeforces - Codeforces Round 910 (Div. 2)
// URL: https://codeforces.com/contest/1898/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include 
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<> n;
    vector a(n), b(n);
    int maxx = INT_MAX, minn = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    int ans = 0;
    int sum = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> b[i];
        sum += abs(a[i] - b[i]);
        int ma = max(a[i], b[i]);
        maxx = min(maxx, ma);
        int mi = min(a[i], b[i]);
        minn = max(minn, mi);
        ans = max(ans, max(minn - ma, mi - maxx));
    }
    cout << ans * 2 + sum << "\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int ___ = 1;
    cin >> ___;
    while (___--)
        solve();
    return 0;
}

你可能感兴趣的:(CF题解,c++,算法)