[VP]CF794 Div2

A. Everything Everywhere All But One

题意:给你一个序列,问是否可以选出其中 \(n-1\) 个数,使其平均值与剩下的那个数相等( \(n\leqslant50\)

解法:暴力枚举

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=2002000,mod=998244353;
const double eps=1e-8;
int a[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        int n=read(),tot=0;
        bool flag=false;
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++){
            tot=0;
            for(int j=1;j<=n;j++){
                if(j!=i) tot+=a[j];
            }
            double res=(double)tot/(n-1);
            if(fabs(res-(double)a[i])<eps) printf("Yes\n"),flag=true;
            if(flag) break;
        }
        if(!flag) printf("No\n");
    }
    return 0;
}

B. Odd Subarrays

题意:给你一个 \(1\sim n\) 的排列,可以将其划分成多个子串,使其中逆序对数量为奇数的子串数目最大
输出最大数目,\(n\leqslant 10^5\)

解法:先手模一个排列,比如 1 3 7 5 6 4 2 8
不难发现将其划分为 1 3 | 7 5 | 6 4 | 2 8 时答案最大
大胆猜想,由于在一个平凡的逆序对 \((a_i,a_j)\)\(\tau=1\) (也就是逆序对数为 \(1\) )满足条件
因此我们可以遇见一个逆序对就划分,这样肯定更优秀
发现他过了,考虑如何证明
比如对于一个序列 \(a_1,a_2,a_3,a_4~(a_3>a_4>a_1>a_2)\) 如果不断开 \(\tau=2\)
如果断开的在 \(a_3\) 后面则答案要 \(+1\) ,比起在 \(a_2\) 处断开 \(ans+2\) 更劣
其余情况不难依此得出

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=2002000,mod=998244353;
int a[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        int n=read();
        int ans=0;
        for(int i=1;i<=n;i++){
            a[i]=read();
            if(a[i]<a[i-1]){
                ans++,i++;
                if(i<=n) a[i]=read();
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C. Circular Local MiniMax

题意:给你一个数组 \(a\) ,问可否将其重新排列成一个环 \(b\) 使所有的 \(b_i\) 均满足

\[b_{i-1}>b_i<b_{i+1}~\operatorname{or}~b_{i-1}<b_i>b_{i+1}~(2\leqslant i\leqslant n) \]

此处令 \(b_{n+1}=b_1\)\(n\leqslant 10^5\)

解法:首先容易注意到如果 \(n\) 是奇数显然无解
然后把数组排一下序,将 \(a_i\)\(a_{i+\frac{n}{2}}\) 放一起
这是因为这样可以最大限度地保证不会安排上两个相同的(下标最小差值更大)
然后扫一遍 \(b\) 数组看是否符合即可

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=2002000,mod=998244353;
int a[WR],rec[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        int n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        if(n&1) printf("No\n");
        else{
            sort(a+1,a+1+n);
            int tot=0;
            for(int i=1;i<=n;i+=2) rec[i]=a[++tot];
            for(int i=2;i<=n;i+=2) rec[i]=a[++tot];
            bool flag=true;
            rec[n+1]=rec[1];
            for(int i=2;i<=n;i++){
                if(rec[i]>rec[i-1]&&rec[i]>rec[i+1]) continue;
                if(rec[i]<rec[i-1]&&rec[i]<rec[i+1]) continue;
                flag=false;break;
            }
            if(flag){
                printf("Yes\n");
                for(int i=1;i<=n;i++) printf("%lld ",rec[i]);
            }else printf("No");
            printf("\n");
        } 
    }
    return 0;
}

D. Linguistics

首先,观察几个字符串
可以发现:若存在形似 \(\mathrm{ABBAABAB}\) 等有两个相同的字符挨在一起的情况,则我们在它们中间放一块隔板
那么,位于同一区间的所有字符都是相间的形式
也就是说,可以用碎片 \(\rm AB\)\(\rm BA\) 来拼凑出它们
当某一区间的字符个数为奇数时,如 \(\rm ABA\)
若想使用 \(\rm AB\)\(\rm BA\) ,则一定会删去一个 \(\rm A\),而具体是哪一个我们并不关心
但删去不同的 \(\rm A\) 则会导致用于表示这一区间的碎片不同
当某一区间的字符个数为偶数时,如 \(\rm ABABABAB\) ,那么最理想的情况是用四个 \(\rm AB\) 来凑这段区间
而当 \(\rm AB\) 不够用的时候,则可以将原区间用 一些 \(\rm AB+A+\) 一些 \(\rm BA+B\)拼凑出来
也就是说,当前区间为偶数时,可以通过使用一个 \(\rm A\)\(\rm B\) 来使得区间使用的碎片发生变化
综上,可以发现,当区间为奇数时,它使用的碎片是不确定的
而当区间为偶数时,它使用的碎片是确定的(偶区间使用的碎片可以使用 \(\rm A\)\(\rm B\) 来改变)
所以,我们先处理区间为偶数时的情况,因为这时使用的碎片确定
当有多个偶数区间使用的碎片都相同时,我们将这些区间按照大小从小到大排序,这是因为不一定能都填满所有的区间
所以我们从长度小的区间开始填,这样,我们就能保证被填满的区间最多,而没有填满的区间使用 \(\rm A\)\(\rm B\) 来进行转换
这样就能确保我们使用的 \(\rm A\)\(\rm B\) 尽可能少
在我们解决完偶区间后,我们考虑奇区间
首先,若当前区间为 \(\rm ABABABABA\) 的形式,则用一个碎片替代最前面或最后面的(相当于删去最前面或最后面的)
这样就能使用 \(\rm AB\)\(\rm BA\) 去填满这个区间
而若我们剩下的或不能靠自己这一类去填满当前区间,也就是我们需要用两种碎片来拼凑同一区间
则我们将碎片替代的字符变成区间中一个非端点字符,此时区间被划分成了两半
左边一半使用的碎片为一种,右边一半使用的碎片为另外一种
综上,对于奇区间,无论怎样用 \(\rm AB\)\(\rm BA\) 拼凑,都只需要用一个 \(\rm A\)\(\rm B\)
所以我们只需要在偶区间操作完后再判断一下 \(\rm A/B\) 的数量 \(+\rm AB\) 的数量 \(+\rm BA\) 的数量是否能填满奇区间即可
对于 \(\rm A/B\):若我们先将奇区间中使用的单个A和B删去后,A和B的数量一定是相等的
因为它们在偶区间中的使用是成对出现的
由于代码意识流,解说转自 https://www.cnblogs.com/LuoyuSitfitw/p/16624323.html

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=2002000,mod=998244353;
char str[WR];
bool vis[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        int a=read(),b=read(),c=read(),d=read();
        scanf("%s",str+1);
        int len=strlen(str+1);
        int cntA=0,cntB=0;
        for(int i=1;i<=len;i++){
            if(str[i]=='A') cntA++;
            else cntB++;
        }
        if(cntA!=a+c+d||cntB!=b+c+d){
            printf("No\n");continue;
        }
        int cntAB=0,cntBA=0;
        vector<int>ab,ba;
        for(int l=1;l<=len;l++){
            int r=l;
            while(r<len&&str[r+1]!=str[r]) r++;
            if((r-l+1)&1){
                if(str[l]=='A') a--;
                else b--;
            }else{
                if(str[l]=='A') ab.emplace_back((r-l+1)>>1),cntAB+=((r-l+1)>>1);
                else ba.emplace_back((r-l+1)>>1),cntBA+=((r-l+1)>>1);
            }
            l=r;
        }
        if(a<0||b<0){
            printf("No\n");
            continue;
        }
        sort(ab.begin(),ab.end());
        int tmp=min(a,b);
        while(!ab.empty()&&tmp){
            tmp--;
            cntAB-=ab.back();
            ab.pop_back();
        }
        if(cntAB>c){
            printf("No\n");
            continue;
        }
        sort(ba.begin(),ba.end());
        tmp=min(a,b);
        while(!ba.empty()&&tmp){
            tmp--;
            cntBA-=ba.back();
            ba.pop_back();
        }
        if(cntBA>d){
            printf("No\n");
            continue;
        }
        printf("Yes\n");
    }
    return 0;
}
posted @ 2022-11-11 19:46  冬天丶的雨  阅读(32)  评论(0编辑  收藏  举报
Live2D