1 条题解

  • 0
    @ 2025-8-24 22:33:16

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar cyffff
    Not yet for the story on the last page, it's not the end.

    搬运于2025-08-24 22:33:16,当前版本为作者最后更新于2021-02-22 16:55:52,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Link\text{Link}

    算法 1

    针对 Subtask 1\text{Subtask 1}

    显然对于询问 11,答案为 rl+1r-l+1,对于询问 22,答案为 11

    时间复杂度 O(n+m)O(n+m)。期望得分 5pts5\text{pts}

    算法 2

    暴力求区间最长不降/上升子序列,时间复杂度 O(mn2)O(mn^2)。期望得分 10pts10\text{pts},结合算法 11 可得 15pts15\text{pts}

    算法 3

    prex,i=j=1i[ai=x]pre_{x,i}=\sum_{j=1}^i[a_i=x],(0x10\le x\le11in1\le i\le n)。

    第一问:

    其实本质是求 $\max_{i=l}^r pre_{0,i}-pre_{0,l-1}+pre_{1,r}-pre_{1,i}$。

    怎么理解这个柿子呢?显然 prepre 是前缀和的形式,所以 pre0,ipre0,l1pre_{0,i}-pre_{0,l-1}j=li[ai=0]\sum_{j=l}^i[a_i=0]pre1,rpre1,ipre_{1,r}-pre_{1,i}j=i+1r[ai=1]\sum_{j=i+1}^r[a_i=1]。我们可以理解 ii 为分界线,分界线前选 00,分界线后选 11,枚举所有 lirl\le i\le r,显然可以取到最大值,时间复杂度 O(mn)O(mn)

    还需要特判只选 11 的情况,当然你也可以看为求 $\displaystyle\max_{i=l-1}^rpre_{0,i}-pre_{0,l-1}+pre_{1,r}-pre_{1,i}$。

    第二问:

    显然有答案为 1122,答案为 22 时只有在有 00 在最后一个 11 前面,否则为 11

    于是我们考虑维护 befibef_iai=1a_i=1ii 前最后一个 00 所在的位置,否则为 00

    答案显然为 1+[(maxi=lrbefi)l]1+[(\max_{i=l}^r bef_i)\ge l],暴力枚举,时间复杂度 O(mn)O(mn)

    总时间复杂度 O(mn)O(mn)。期望得分 25pts25\text{pts}

    算法 4

    上面那个东西可以套路ST表处理,时间复杂度 O(nlogn+m)O(n\log n+m),期望得分 100pts100\text{pts}

    当然开 22 个ST表常数较大。

    +1-1RMQ 可以做到严格 O(n+m)O(n+m),常数较大,不做为本题最优做法。

    这里还有一个后来发现的一个减小常数方法:

    发现第二问只有 1122 两种答案,要有 22 则区间中必须出现连续的 010-1,于是我们维护 010-1 出现次数的前缀和,如果左端点前缀和等于右端点前缀和,则答案为 11,否则为 22。可以大大减小常数,如果实现优秀,则可以所有点进 1s。

    #include<bits/stdc++.h>
    using namespace std;
    namespace IO{//by cyffff
    	
    }
    const int N=1e6+10;
    int n,m,st[20][N],lg[N],a[N],pre[N],pp[N];
    inline int query(int l,int r){
    	int q=lg[r-l+1];
    	return max(st[q][l],st[q][r-(1<<q)+1]);
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++){
        	a[i]=read();
    	}
    	a[0]=2;
    	int sum=0,o=0,z=0;
    	for(int i=1;i<=n;i++){
    		if(a[i]) sum--,o++;
    		else sum++,z++;
    		st[0][i]=z-o;
    		pp[i]=o;
    		pre[i]=pre[i-1]+(a[i]==1&&a[i-1]==0);
    	}
    	for(int i=2;i<=n;i++)
    	    lg[i]=lg[i>>1]+1;
    	for(int i=1;i<=19;i++)
    		for(int j=1;j+(1<<i)-1<=n;j++)
    			st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
    	for(int i=1;i<=m;i++){
    		int opt=read(),l=read(),r=read();
    		if(opt==1)
    			write(max(pp[r]-pp[l-1],query(l,r)-(l-1-pp[l-1])+pp[r]));
    		else
    			write(1+!(pre[l]==pre[r]));
    		putc('\n');
    	}
    	flush();
        return 0;
    }
    

    再见 qwq~

    upd:好像赛时还被线段树过了,考虑加入主题库后缩小时限。

    • 1

    信息

    ID
    6519
    时间
    2000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者