CF1291

CF1291A

个人做法:如果是偶数就把末尾的偶数全删了 数位加起来不满足的话找个奇数删了就行

然后没判前导0 WA了3发

实际上找两个奇数直接输出即可

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[N],sum,flag,frt;
char c;
signed main(){
    t=read();
    while(t--){
        n=read();sum=flag=0;frt=1;
        for(int i=1;i<=n;i++){
            scanf(" %c",&c);
            a[i]=c-'0';
        }
        while(n&&!(a[n]&1))n--;
        if(!n){puts("-1");continue;}
        for(int i=1;i<=n;i++)sum+=a[i];
        if(sum&1){
            for(int i=n-1;i;i--)
                if(a[i]&1){flag=i;break;}
            if(!flag){puts("-1");continue;}
            if(n==1){puts("-1");continue;}
        }
        for(int i=1;i<=n;i++){
            if(i==flag)continue;
            if(frt&&!a[i])continue;
            write(a[i]);frt&=!(bool)a[i];
        }
        if(frt){puts("0");continue;}
        puts("");
    }
    return 0;
}

CF1291B

贪心。

发现如果原来中间位置就满足要求 右移后右边一定也满足 那么对于两边都贪心的多选

且对于左边 只要每个位上的数分别比 0,1,2...大 那么减到该状态一定最优 右边同理

最后判一下两侧满足区间是否有交集即可

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[N],l,r;
char c;
signed main(){
    t=read();
    while(t--){
        n=read();l=0,r=n+1;
        for(int i=1;i<=n;i++)a[i]=read();
        while(l+1<=n&&a[l+1]>=l)l++;
        while(r-1>=1&&a[r-1]>=n-r+1)r--;
        puts(l>=r?"YES":"NO");
    }
    return 0;
}

CF1291C

首先 我们只看自己前面的 \(m-1\)

我们可以枚举自己操纵的人有几个取前面 对单个情况的最坏答案取max

单个情况也可直接枚举 暴力 \(O(n^2)\) 可以过

发现每种情况都会有状态被重复取过 可以单调队列优化到 \(O(n)\)

\(n<=3500\) 写啥正解啊 暴力不香吗

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,k,a[N],ans,res;
char c;
signed main(){
    t=read();
    while(t--){
        n=read();m=read();k=read();ans=0;
        for(int i=1;i<=n;i++)a[i]=read();
        if(k>=m-1){
            for(int i=1;i<=m;i++)ans=max(ans,a[i]);
            for(int i=n;i>=n-m+1;i--)ans=max(ans,a[i]);
            writel(ans);continue;
        }
        for(int i=1;i<=k+1;i++){
            res=inf;
            for(int j=i;j<=i+m-k-1;j++){
                res=min(res,max(a[j],a[j+n-m]));
            }
            ans=max(ans,res);
        }
        writel(ans);
    }
    return 0;
}

CF1291D

看完题解才知道这是构造+结论题。

首先这操作相当于把原串打乱 使无论咋分段每段元素和原来比一定有至少一个不同

考虑几种情况:

  • \(l=r\) 一定可以(一个没法分)
  • \(s[l]\not=s[r]\)\(s[l]\) 放到最左面 \(s[r]\) 放到最右 一定满足
  • 否则看区间字母数量 \(cnt\ge 3\) 一定满足
    证明:设此时 \(s[l]=s[r]=x\) 其他位置必有 \(y\ z\)(第二条不满足)
    那么把 \(y\) 放最左 \(z\) 放最右
    这样想让两种元素一起出现 必须要把整个串全选上 这样就不满足要求

剩下情况puts(“No”)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,k,a[N],ans,res,sum[N][30],q,l,r;
char s[N];
signed main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=26;j++)
            sum[i][j]=sum[i-1][j]+(s[i]-'a'+1==j);
    q=read();
    while(q--){
        l=read();r=read();
        if(l==r){puts("Yes");continue;}
        if(s[l]^s[r]){puts("Yes");continue;}
        int cnt=0;
        for(int i=1;i<=26;i++)cnt+=(bool)(sum[r][i]-sum[l-1][i]);
        if(cnt>=3)puts("Yes");
        else puts("No");
    }
    return 0;
}

CF1291E

题解看好久才看懂 果然还是太蒟了

重要性质:任意三个子集的交集为空集

即每个位置最多出现两次

考虑对于每个位置:

  • \(s[i]=0\) 两次操作任选其一(不能都选 也不能不选)
  • \(s[i]=1\) 两次操作必须都选/都不选

(不会一次操作做两次 这操作相当于异或 两次就白做了)

考虑用扩展域并查集维护这个操作 一层是选当前操作 一层不选

  • \(s[i]=0\) A操作选--> B操作不选 A操作不选--> B操作选
  • \(s[i]=1\) A操作选--> B操作选 A操作不选--> B操作不选

那么对于只出现一次的操作呢

建立虚拟操作0:

  • \(s[i]=0\) A操作选--> 0操作不选 A操作不选--> 0操作选
  • \(s[i]=1\) A操作选--> 0操作选 A操作不选--> 0操作不选

0操作选不了 最后让0强制不选才是正确答案

合并时维护每个联通块上下两层的大小 维护合并到当前位置 \(ans\) 大小 两层都算了除2即可

(如果第一层小 那么答案就选0了 换成第二层不选0的即可)

这题细节比较多 预处理要带0 操作数需要++

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=1e6+5;
const int M=1e5+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,k,c,fa[N],col[N][2],siz[N][2],x,ans;
char s[N];
inl int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inl void merge(int x,int y){
    x=find(x),y=find(y);
    if(x==y)return;
    ans-=min(siz[x][0],siz[x][1])+min(siz[y][0],siz[y][1]);
    fa[y]=x;siz[x][0]+=siz[y][0];siz[x][1]+=siz[y][1];
    ans+=min(siz[x][0],siz[x][1]);
}
signed main(){
    n=read();k=read()+1;
    scanf("%s",s+1);
    for(int i=0;i<=(k<<1);i++){
        fa[i]=i;
        siz[i][i>=k]=1;
    }
    for(int i=1;i<k;i++){
        c=read();
        while(c--){
            x=read();
            col[x][(bool)col[x][0]]=i;
        }
    }
    for(int i=1;i<=n;i++){
        if(s[i]-'0'){
            merge(col[i][0],col[i][1]);
            merge(col[i][0]+k,col[i][1]+k);
        }else{
            merge(col[i][0],col[i][1]+k);
            merge(col[i][1],col[i][0]+k);
        }
        int x=find(0);
        if(siz[x][0]>siz[x][1])writel(ans>>1);
        else writel((ans>>1)-siz[x][0]+siz[x][1]);
    }
    return 0;
}

CF1291F

不会。

posted @ 2023-10-27 11:49  xiang_xiang  阅读(370)  评论(0编辑  收藏  举报