Codeforces Round #767 (Div. 2) C~D

地址:https://codeforces.com/contest/1629/problem/C

 

 

给出长度为 n 的数列a,现在要经过下面操作构造数列 b:

选出数列 a 中前 k 个数,将前 k 个数的 MEX 值插入到数列 b 末尾。然后删除 a 中的这前 k 个数。
问,如何操作使得构造的数列 b 的字典序最大?

思路
为了使得字典序最大,就要每次都挑选当前整个数列 a 能够达到的最大 MEX 放到数列 b 后面。
同时,为了让 b 的长度尽可能长,从前往后走的过程中,走过的数只要能够构成最大 MEX 了,就退出。让下面的数再尽量产生更多的数。

所以

从前往后维护当前位置到最后一个位置能够达到的最大 MEX 值。
从前往后走,如果走到当前位置发现达到了当前位置存储的最大 MEX 值,那么往后走就没有意义了,退出。
再重新往后走。
如何求一个数列每次加上当前位置后的 MEX 值呢?
如果一个数出现过了,就将其标记下来。用一个指针index表示到当前位置的 MEX 值。 

#include <bits/stdc++.h>
using namespace std;
int T,a[200005],cnt[200005],st[200005],d[200005];
//注意数组大小开成1e6+10时就会超时,经过测试速度慢了四倍
int main(){
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        int a[n+1];
        memset(cnt,0,sizeof(cnt));//记录这个点出现的次数
        memset(st,0,sizeof(st));//标记
        for(int i=1;i<=n;i++){
            cin>>a[i];
            cnt[a[i]]++;
        }
        int index=0,res=0;//从0开始找mex
        for(int i=1;i<=n;i++){
            cnt[a[i]]--;//该点剩余可用次数-1
            st[a[i]]=1;//这个点被扫描过了
            while(st[index]) index++;//找到mex的值,即还没被扫描过的最小整数
            if(cnt[index]==0){ //该值无剩余
                d[res++]=index; //放入新开的数组
                index=0;//重新从0开始找mex
                memset(st,0,sizeof(st));//状态清空
            }
        }
        cout<<res<<endl;//输出新开数组的长度和值
        for(int l=0;l<res;l++)
            cout<<d[l]<<" ";
        cout<<endl;

    }
}

 

 地址:https://codeforces.com/contest/1629/problem/D


题意:

给出 n 个字符串,每个长度不超过3。
问,是否存在几个字符串,按顺序连接之后是回文串? 

思路:

如果回文串长度为1,直接判断所有字符串。
否则,那么组成该回文串的字符串一定为2或3。那么回文串最开始的一个字符串一定也能和最后面的一个字符串连接后形成回文串。
所以只需要判断两个串连接之后是否形成回文串即可。

#include <bits/stdc++.h>
using namespace std; ;

const int  N=1e5+10;
string a[N];
int n,T;
map<string,int>mp;

int main(){
    cin>>T;
    while(T--){
        cin>>n;
        int flag=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        mp.clear();
        for(int i=1;i<=n;i++)
        {
            string s=a[i], t=s;
            reverse(s.begin(), s.end());//翻转
            if(s.size() == 1) flag=1;//长度为1的字符串一定是回文的
            if(s==t || mp[s]) flag=1;//逆序等于自身的或存在可匹配成回文的
            for(int j=0;j<26;j++)//判断长度为2的字符串
            {
                //如对于ab,翻转后为ba,只需要存在ba+a|b|c....|z就能构成回文
                string b;
                b = s+char(j+'a');//第三个字符任意
                if(mp[b]) flag=1;//记录可与之匹配的
            }
            string b;//判断长度为3的字符串
            //得到长度为2的前缀,如bac翻转后为cab,得到ca,只要存在ca,就能构成回文
            for(int j=0;j<s.size()-1;j++) b+=s[j];
            if(mp[b]) flag=1;
            mp[t] = 1;//记录当前遍历到的字符串
        }

        if(flag) cout<<"YES\n";
        else cout<<"NO\n";

    }
}

 

posted @ 2022-03-09 23:32  怀义💭🚀🎈  阅读(33)  评论(0)    收藏  举报