Codeforces Round 849 (Div. 4)

目录

A. Codeforces Checking

B. Following Directions

C. Prepend and Append

D. Distinct Split

E. Negatives and Positives

F. Range Update Point Query

G1. Teleporters (Easy Version)

G2. Teleporters (Hard Version)


A. Codeforces Checking


简单题简单处理即可

void solve()
{
    string b; cin>>b;
    if(a.find(b)!=-1) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
        return ;
}

B. Following Directions


简单模拟

void solve()
{
    string s; cin>>n>>s;
    int x=0,y=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='U') y++; 
        if(s[i]=='R') x++;
        if(s[i]=='L') x--;
        if(s[i]=='D') y--;
        if(x==1&&y==1)
        {
            cout<<"YES"<<endl;
            return ;
        }
    }
    cout<<"NO"<<endl;
        return ;
}

C. Prepend and Append


简单两边同时移动即可

void solve()
{
    string s; cin>>n>>s;

    s=' '+s;
    for(int i=1,j=n;i<=j;i++,j--)
    {
        if((s[i]-'0')+(s[j]-'0')!=1) 
        {
            cout<<j-i+1<<endl;
            return ;
        }
    }
    cout<<0<<endl;
        return ;
}

典型


D. Distinct Split


我们发现一直是从中间某一个位置划开也就是一段要么是前面的要么是后面的也就是说
我们可以发现如果后面的没了也就是前面的有了我们可以直接从前面来变化记录后面的
变化同时就可以记录前面的变化

也可以傻傻的使用树状数组(不推荐)局限性

void solve()
{
    cin>>n;
    mp1.clear(),mp2.clear();
    string s; cin>>s;
    int ans1=0,ans2=0;
    for(int i=0;i<n;i++)
    {
        if(!mp2[s[i]]) ans2++;
        mp2[s[i]]++;
    }
    int ans=ans2;
    for(int i=0;i<n;i++)
    {
        if(!mp1[s[i]]) ans1++;
        mp1[s[i]]++;

        mp2[s[i]]--;

        if(mp2[s[i]]==0) ans2--;
        ans=max(ans,ans1+ans2);
    }
    cout<<ans<<endl;

E. Negatives and Positives


发现性质最后一定是都会处理到所以的话我们判断负数的个数,0的个数结合贪心最大的负数和最最小的正数即可

void solve()
{
    cin>>n;
    vector<int> z,f;
    int cnt=0;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        if(x==0) cnt++;
        else{
            if(x>0) z.push_back(x);
            else f.push_back(x);
        }
    }
    sort(z.begin(),z.end());
    sort(f.begin(),f.end(),greater<int>());

    LL ans=0;
    for(auto&v:z) ans+=v;
    for(auto&v:f) ans-=v;

    if(cnt || f.size()%2==0){

    } 
    else{
        if(z.empty()) ans+=2*f[0];// 全是负数同时它是奇数
        else ans=ans-z[0]+f[0]+max(-z[0]-f[0],z[0]+f[0]);
    }

    cout<<ans<<endl;

    return ;
}

F. Range Update Point Query


我们发现这种操作次数不是很多的同时是维护区间性质的,维护区间的变化同时又要查询我们可以考虑使用树状数组

struct BIT{
    int tr[N];
    int inline lowbit(int x){
        return x&(-x);
    };
    void add(int k,int x){
        for(int i=k;i<=n;i+=lowbit(i)) tr[i]+=x;
    };
    int query(int k){
        int res=0;
        for(int i=k;i;i-=lowbit(i)) res+=tr[i];
        return res;
    };
}tree;

void solve()
{
    cin>>n>>m;

    vector<int> a(n+5);

    for(int i=1;i<=n;i++) cin>>a[i];

    for(int i=1;i<=n+5;i++) tree.tr[i]=0;

    while(m--){
        int op,l,r,x; 
        cin>>op;
        if(op==1){
            cin>>l>>r;
            tree.add(l,1),tree.add(r+1,-1);
        }
        else{
            cin>>x;
            int tim=tree.query(x);
            int w=a[x];
            while(tim>0 && w>=10){
                int now=0;
                while(w){
                    now+=w%10;
                    w/=10;
                }
                w=now;
                tim--;
            }
            cout<<w<<endl;
        }
    }

    return ;
}

ps:同时我们可以发现操作次数不算多用了之后有些区间就消失了所以可以使用二分+set

int change(int x)
{
    int res=0;
    while(x) res+=x%10,x/=10;
    return res;
}
void solve()
{
    cin>>n>>m;
    q.clear();
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(a[i]>=10) q.insert(i);
    }

    while(m--)
    {
        int x; cin>>x;
        if(x==1){
            int l,r; cin>>l>>r;
            auto rr=q.upper_bound(r);
            auto ll=q.lower_bound(l);
            for(auto i=ll;i!=rr;)// 遍历次数不会太多比如999999   也就54 那么也就遍历3n就没了
            {
                auto it=*i;
                if(a[it]>=10) a[it]=change(a[it]);
                if(a[it]<10) i=q.erase(i);
                else i++;
            }
        }
        else {
            int y; cin>>y;
            cout<<a[y]<<endl;
        }
    }
        return ;
}

G1. Teleporters (Easy Version)


我们发现一个传送器的贡献是a[i]+i,所以我们直接从小到大最优的选取即可

int a[N];
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[i]+=i;
    }
    sort(a+1,a+1+n);
    int ans=0;
    for(int i=1;i<=n;i++)
    if(m>=a[i]) m-=a[i],ans++;
    else break;
    cout<<ans<<endl;
        return ;
}

G2. Teleporters (Hard Version)


我们考虑这样一个问题也就是如果上一个点走完了我去完0或者是n+1都是可以的取决于谁带来的贡献小,于是有这样一个贪心,每一个点一定是从左边或者右边来的,接着第一个点一定是从左边来的所有我们枚举第一个点的位置减去他的共享接着来算选了多少个点,如果重复算了这个点的话我们就重新计算他带来的贡献即可

LL a[N],b[N],c[N],sum[N];
LL find(LL x)
{
    LL l=0,r=n;
    while(l<r){
        LL mid=l+r+1>>1;
        if(sum[mid]>x) r=mid-1;
        else l=mid;  
    }
    return l;
}
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];// 初始序列
        b[i]=min(a[i]+i,a[i]+n-i+1);// 最优序列
        c[i]=b[i];// 初始最优序列
    }

    sort(b+1,b+1+n);// 对最优序列排序
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+b[i];// 前缀和
    LL ans=0;
    for(int i=1;i<=n;i++){
        LL res=m;
        if(a[i]+i>res) continue;
        res-=(a[i]+i); 
        LL l=find(res);
        if(b[l]<c[i]) ans=max(ans,l+1);// 表示比排序后的还要大表示不会多算自己
        else ans=max(ans,find(res+c[i]));// 表示这个点重复算了加上他重复的贡献即可

    }

    cout<<ans<<endl;
        return ;
}

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值