Codeforces Round #767 (Div. 2) 小结

Problem A

Download More RAM

思路

签到题,将软件按\(a_i\)值从小到大排序,模拟即可。

Problem B

GCD Arrays

思路

同样是签到题,由于给定的是一段连续自然数,我们令最终的gcd=2即可,这样操作次数是最少的。简单来说,我们将一个奇数和一个偶数合并,最小操作次数就是这段区间内奇数的个数。

若奇数个数 \(\geq k\) 则无解。

注意特判 \(l=r\) 的情况

Problem C

Meximum Array

思路

用了一种比较奇特的做法

yy一下可知,贪心算法是可行的,每一次取当前最大的mex值,当存在mex相同时,取最靠前的。

怎样维护mex以及找到mex最大的位置?

既然这是一道Div2的C题,那么高级数据结构就不用考虑了,不会那么难。(我还傻乎乎地考虑了怎么动态维护区间Mex。。。)

注意到题目条件\(0 \leq a_i \leq n\),这启示我们从值域上去考虑。

维护每一个\(a_i\)第一次出现的位置\(p[a[i]]\),依次验证是否存在 \(j\) 使 \(mex[j]=0,1,2...\)

如果存在\(mex[j]=x\),那么必然有\(j\geq max(p[0],p[i],...,p[x-1])\)且等号能取到。

于是我们就确定了应该取数的值和位置(当首次发现\(x\)不存在对应的\(j\)时,因为mex不能取到x+1了)。

我在说些什么。。。[笑哭](结合代码理解吧)

代码

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxn 200010
using namespace std;
int a[maxn];
int nxt[maxn],pre[maxn],fst[maxn],last[maxn];
int b[maxn],cnt=0;
void init(int n){
    cnt=0;
    for(int i=0;i<=n;++i){
        nxt[i]=fst[i]=pre[i]=last[i]=0;
    }
}
int main(){
    int i,j;
    int t;
    int n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(i=1;i<=n;++i) scanf("%d",&a[i]);
        init(n);
        for(i=1;i<=n;++i){
            if(!last[a[i]]) fst[a[i]]=i;
            pre[i]=last[a[i]];
            last[a[i]]=i;
            nxt[pre[i]]=i;
        }
        int p=0,q=1;
        while(q<=n){
            if(q==n){
                if(a[q]==0) b[++cnt]=1;
                else b[++cnt]=0;
                break;
            }
            for(i=0;i<=n;++i){
                if(!fst[i]) break;
                p=max(p,fst[i]);
            }
            b[++cnt]=i;
            if(i==0){
                p=q;
                fst[a[p]]=nxt[p];
            }
            else{
                for(i=q;i<=p;++i){
                    if(nxt[i]<=p&&nxt[i]>0) continue;
                    fst[a[i]]=nxt[i];
                }
            }
            q=p+1;
        }
        printf("%d\n",cnt);
        for(i=1;i<=cnt;++i){
            printf("%d ",b[i]);
        }
        printf("\n");
    }
    // system("pause");
    return 0;
}

Problem D

Peculiar Movie Preferences

比赛时想到了正解,但是时间不够没调出来。

思路

首先如果给定的字串\(s\)中本来就有回文串(包括长度为1的串),那必然YES。

于是我们可以认为只有长度为2和3的串。

手玩下样例,猜个结论:若存在回文串,必然存在两个原串拼起来的回文串(证明见tutorial)。

然后就做完了。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define maxn 100010
using namespace std;
char s[maxn][4];
int book[27][27][27],ans=0;
void init(){
    int i,j,k;
    ans=0;
    for(i=0;i<=26;++i)
        for(j=0;j<=26;++j)
            for(k=0;k<=26;++k)
                book[i][j][k]=0;
}
int main(){
    int i,j,n,m;
    int T;
    scanf("%d",&T);
    while(T--){
        int flag=0;
        scanf("%d",&n);
        init();
        for(i=1;i<=n;++i) scanf("%s",s[i]);
        for(i=1;i<=n;++i){
            int L=strlen(s[i]);
            if(L==1||L==3&&s[i][0]==s[i][2]||L==2&&s[i][0]==s[i][1]){
                flag=1;
                break;
            }
        }
        if(flag) ans=1;
        else{
            for(i=1;i<=n;++i){
                int x,y,z;
                if(strlen(s[i])==2){
                    x=s[i][0]-'a'+1;
                    y=s[i][1]-'a'+1;
                    z=0;
                    for(j=0;j<=26;++j){
                        if(book[y][x][j]){
                            ans=1;
                            break;
                        }
                    }
                    book[x][y][0]=1;
                    if(ans) break;
                }
                else{
                    x=s[i][0]-'a'+1;
                    y=s[i][1]-'a'+1;
                    z=s[i][2]-'a'+1;
                    if(book[z][y][x]||book[z][y][0]){
                        ans=1;
                        break;
                    }
                    book[x][y][z]=1;
                    if(ans) break;
                }
            }
        }
        if(ans) printf("YES\n");
        else printf("NO\n");
    }
    // system("pause");
    return 0;
}

还是得提升中档题的思考速度啊QWQ

posted @ 2022-03-02 23:56  文艺平衡树  阅读(26)  评论(0编辑  收藏  举报