首页 > 其他分享 >[VP]CF794 Div2

[VP]CF794 Div2

时间:2022-11-11 19:56:44浏览次数:75  
标签:ch int VP CF794 WR 区间 rm include 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;
}

标签:ch,int,VP,CF794,WR,区间,rm,include,Div2
From: https://www.cnblogs.com/WintersRain/p/16881259.html

相关文章