Codeforves 535 div3 模拟

本文深入解析了算法竞赛中各类题目策略,包括坐标压缩、数字拆解、字符串操作、颜色匹配等,重点介绍了复杂数据结构如线段树的应用,以及如何通过优化算法提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. 水题。。两个坐标重合之后看一下

B.拆数字,我们知道最大的肯定是一个,第二个我们可以从大到小遍历,找到一个不会被最大值整除的或者连续出现两次的

因为只看最大和次打 可以被 hack 掉  

参照 10 5 2 2 1 

C. 题意很墨迹,有三个灯, r g b 我们要求 r 与 r 之间 , g 与 g 之间 以及 b 与 b 之间距离必须被3整除,

给你一个只含 rgb 的字符串,在最小修改次数的情况下,修改使得这个字符串符合条件

我们自己推一下发现,只能是 RGBRGBRGB..... 或者 GRBGRBGRB....等6种情况,之后暴力比对,选最小的一种更新

D. 和上一题背景相同,只不过要求相邻的颜色不能一样,求最小修改

那么我们发现 RRR 的话 修改中间显然最少, RRG 就把中间改成 B RRB 改成 G。。。暴力 if 判断

E1 简单版本。。很重要,会简单版本才能对困难版本有更好的优化思路

我们知道 选择减的区间,如果最小值在里边而最大值不在里边肯定是最好结果,那么如果 n = 300 那么很显然,我们完全可以暴力枚举 最大点和 最小点, 然后求出最大极差, 更新坐标就好了

E2 hard 版本,数据范围 n 在 1e5但是 m 没有变。暴力枚举肯定不成立了,还是那个思想,最小值尽可能多减去,最大值尽可能选在使用区间外部

求区间最大值,我们一下就可以想到线段树维护,之后我们仍然跑一边 N, 枚举每个 i ( i belong 1-n ) 作为最小值,那么显然,以 i 作为起点的区间和 包住 i  的区间还有以 i 为 终点的区间,我们都要用上,而对于外部的,我们尽可能不用,因为会对整个区间最大值产生影响,所以我们要看的知识最小值,最大值直接根据当前情况推出就好了,当然如果 i 是某个区间终点,我们在跑完 i 之后就要回收这个区间,因为 如果不去回收那么很显然会对整体最大值产生影响,所以回溯一下就好了。。。

附代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
inline int read()
{
    register int s=0,w=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
vector<int> st[maxn],ed[maxn],anss;
#define pb(a) push_back(a)
struct que
{
    int l,r;
}q[maxn];
int n,m,a[maxn];
struct node
{
    int mx, add;
    int l, r;
}tr[maxn<<2];
#define ls rt<<1
#define rs rt<<1|1
inline void pushdown(int rt)
{
    if(tr[rt].add != 0)
    {
        tr[ls].add += tr[rt].add; tr[ls].mx += tr[rt].add;
        tr[rs].add += tr[rt].add; tr[rs].mx += tr[rt].add;
        tr[rt].add = 0;
    }
}
inline void pushup(int rt){tr[rt].mx = max(tr[ls].mx, tr[rs].mx);}
inline void build(int rt, int l, int r)
{
    tr[rt].l = l; tr[rt].r = r;
    if(l == r)
    {
        tr[rt].mx = a[l];
        tr[rt].add = 0;
        return;
    }
    int mid = (l+r)>>1;
    build(ls, l, mid);
    build(rs, mid+1, r);
    pushup(rt);
}
inline void update(int rt, int ql, int qr, int add)
{
    int l = tr[rt].l, r = tr[rt].r;
    if(l >= ql && r <= qr)
    {
        tr[rt].mx += add;
        tr[rt].add += add;
        return;
    }
    pushdown(rt);
    int mid = (l+r)>>1;
    if(mid >= ql) update(ls, ql, qr, add);
    if(mid < qr) update(rs, ql, qr, add);
    pushup(rt);
}
inline int query(int rt, int ql ,int qr)
{
    int l = tr[rt].l, r = tr[rt].r;
    if(l >= ql && r <= qr)
        return tr[rt].mx;
    int ans = -0x3f3f3f3f;
    pushdown(rt);
    int mid = (l+r)>>1;
    if(ql <= mid) ans = max(ans, query(ls, ql, qr));
    if(qr > mid) ans = max(ans, query(rs, ql, qr));
    return ans;
}
int main()
{
    n=read(),m=read();
    int mx = -0x3f3f3f3f, mn = 0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        mx=max(mx,a[i]);
        mn=min(mn,a[i]);
    }
    int ans = mx-mn;
    build(1, 1, n);
    for(int i=1;i<=m;i++)
    {
        q[i].l=read(),q[i].r=read();
        int s = q[i].l, e = q[i].r;
        st[s].pb(e); ed[e].pb(s);
    }
    int id = 0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<st[i].size();j++)
        {
            int t = st[i][j];
            update(1, i, t, -1);
        }
        int temp = query(1, 1, n) - query(1, i, i);
        if(temp > ans)
        {
            ans = temp; id = i;
        }
        for(int j=0;j<ed[i].size();j++)
        {
            int t = ed[i][j];
            update(1, t, i, 1);
        }
    }
    cout<<ans<<endl;
    for(int i=1;i<=m;i++)
        if(q[i].l <= id && q[i].r >= id)
            anss.pb(i);
    cout<<anss.size()<<endl;
    for(int i=0;i<anss.size();i++)
        cout<<anss[i]<<' ';
    return 0;
}

F 题意看了个大概。。不会。。。日后在解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值