Codeforces Round #767 (Div. 2)

呜,一学期都没打cf,久而久之变得生疏和害怕了,寒假第一场cf就如此...惨烈,不过也是随着补题才有提升嘛。

C. Meximum Array

mex...之前只在博弈论之类的见到过...没自己实现过呜。

这题很重要的一点是对于固定起点的一系列前缀求mex数组的话,这个数组是单调不减的,并且上升速度不会超过1/1

也就是说,我们设当前位置作为末尾的数组的mex值为 j 的话,每次移动位置后,只要将原数组当前位置的值在mark数组中做好标记,然后让 j  一直++直到遇到未标记的位置,这个 j 就是当前位置作为末尾的数组的mex值。

以上是线性时间复杂度求前缀mex的办法,此题还有个关键是要记录mex数组第一次达到最大值的位置,我一开始想的是,每次增长就记录一下位置,最后自然得到结果。但是这个方法实际上复杂度过高了,因为很有可能2*105的数组只要4位mex就达到了最大(test 2),O(n2)中每次后面的计算都是多余的,因为每个都计算了n次。

这时候灵机一动发现,只要我提前用O(n)算出后缀的mex,那么第一次达到最大也就只要比较 j 等于后缀的mex就行了。注意这里的后缀的开头是指上一次循环中记录的第一次最大位置,也是这次的开始位置(即使在补题时还是大意吃了发WA(悲))。

AC代码:

#include <bits/stdc++.h>
#define ll long long
#define F freopen("in.txt", "r", stdin)
using namespace std;
int num[200005], mrk[200005], mex2[200005];
int main()
{
    //F;
    int t;
    cin >> t;
    while (t--)
    {
        vector<int> ans;
        int n;
        cin >> n;
        int x = 1;
        for (int i = 1; i <= n; i++)
            cin >> num[i];
        int j2 = 0;
        for (int i = n; i > 0; i--)
        {
            mrk[num[i]] = true;
            while (mrk[j2])
                j2++;
            mex2[i] = j2;
        }
        memset(mrk, 0, sizeof(mrk));
        while (x <= n)
        {
            //cout << "x:" << x << " ";
            int j = 0, maxj = 0;
            for (int i = x; i <= n; i++)
            {
                mrk[num[i]] = true;
                while (mrk[j])
                    j++;
                if (j == mex2[x] || i == n)
                {
                    maxj = j;
                    x = i + 1;
                    break;
                }
            }
            ans.push_back(maxj);
            memset(mrk, 0, sizeof(mrk));
        }
        int st = ans.size();
        cout << st << endl;
        for (int i = 0; i < st; i++)
            cout << ans[i] << (i == st - 1 ? "" : " ");
        cout << endl;
        memset(mex2, 0, sizeof(mex2));
    }
    return 0;
}

 

D. Peculiar Movie Preferences

这题草草看了就没细想了,没想到这么简单...1700*可能是因为很多人在C花了很多时间...个人感觉在如果放C题也是1400*

这题有几个关键点,首先单个字母必定是回文,遇到直接输出yes结束此轮循环即可

于是问题变成考虑长度为2、3的两种字符串的组合,并且可以证明如果超过2个的字符串组合是回文,那么一定存在2个字符串组成的回文。

下面就是实现问题,这里我用集合来处理,每次在集合中查询以前有没有出现过其回文并否则就更新集合。

不慎又WA了几发...一次是忘了考虑3长度字符串的拼接...比如abc+cba,一次是没注意到要求按顺序拼接,只能ab+dba但是不能dba+ab。

AC代码:

#include <bits/stdc++.h>
#define F freopen("in.txt", "r", stdin)
using namespace std;
string str[100005];
int main()
{
    //F;
    int t;
    cin >> t;
    while (t--)
    {
        set<string> s1, s2, s3;
        int n, p = 1;
        cin >> n;
        for (int i = 0; i < n; i++)
            cin >> str[i];
        for (int i = 0; i < n; i++)
        {
            if (str[i].size() == 1)
            {
                cout << "yes" << endl;
                p = 0;
                break;
            }
            if (str[i].size() == 2)
            {
                if (str[i][0] == str[i][1])
                {
                    cout << "yes" << endl;
                    p = 0;
                    break;
                }
                else
                {
                    char sv_c[3] = {str[i][1], str[i][0]};
                    string sv(sv_c);
                    if (s1.count(sv) || s2.count(sv))
                    {
                        cout << "yes" << endl;
                        p = 0;
                        break;
                    }
                    else
                        s1.insert(str[i]);
                }
            }
            if (str[i].size() == 3)
            {
                if (str[i][0] == str[i][2])
                {
                    cout << "yes" << endl;
                    p = 0;
                    break;
                }
                else
                {
                    char sv_c[3] = {str[i][2], str[i][1]};
                    string sv(sv_c);
                    char sv3_c[4] = {str[i][2], str[i][1], str[i][0]};
                    string sv3(sv3_c);
                    if (s1.count(sv) || s3.count(sv3))
                    {
                        cout << "yes" << endl;
                        p = 0;
                        break;
                    }
                    else
                    {
                        char s_c[3] = {str[i][0], str[i][1]};
                        string st2(s_c);
                        s2.insert(st2);
                        s3.insert(str[i]);
                    }
                }
            }
        }
        if (p)
            cout << "no" << endl;
    }
    return 0;
}

 

posted @ 2022-01-23 14:49  Slithery  阅读(105)  评论(0)    收藏  举报