• CodeForces 631C Report「思维题」


    题目描述

    题意翻译

    给定 (n) 个整数组成的序列和 (m) 个操作,每个操作给定 (t_i)(r_i),操作分为两种:

    • (t_i)(1),则将前 (r_i) 个数按照连续不减序(从小到大)排列;
    • (t_i)(2),则将前 (r_i) 个数按照连续不增序(从大到小)排列。

    (m) 次操作过后的序列。

    输入输出样例

    输入 #1

    3 1
    1 2 3
    2 2
    

    输出 #1

    2 1 3 
    

    输入 #2

    4 2
    1 2 4 3
    2 3
    1 2
    

    输出 #2

    2 4 1 3 
    

    思路分析

    疫情期间把这题水过了,突然想回来补锅

    • 题面翻译的非常简洁明了又准确。不知道有多少人像我一样只优化了一丢丢就开始sort
    • 然后应该基本上都会想到这个很显然的性质:如果前面的修改操作的右端点小于后面操作的右端点,那么这次操作其实就是无效的,因为会被覆盖掉
    • 所以就很容易挑选出有效的操作次数,而被筛选操作是这样的:编号越小的修改所覆盖的区间越大,也就是覆盖区间的长度是单调递减的。如果不满足单调递减,那么前面一定会有操作会被覆盖。
    • 那么这个性质怎么用?其实上面说了,就是因为 sort 太多了所以 (TLE) 掉了,而这时候在这个性质下,完全不必 sort,而是可以直接赋值的。方法就是先排序,然后两次被挑选出的操作的端点之间直接赋值。在上面的性质的下,这样的正确性是有保证的

    详见代码

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define R register
    #define N 200010
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m,a[N],c[N],flag[N];
    struct data{
    	int opt,pos;
    }b[N];
    inline bool cmp(int x,int y){return x>y;}
    int main(){
    	n = read(),m = read();
    	for(R int i = 1;i <= n;i++)a[i] = read();
    	for(R int i = 1;i <= m;i++){
    		b[i].opt = read(),b[i].pos = read();
    	}
    	int mx = 0;
    	for(R int i = m;i;i--){//倒序处理出每次操作的后面的操作覆盖的最大区间
    		flag[i] = mx;
    		mx = max(mx,b[i].pos);
    	}
    	for(R int i = 1;i <= mx;i++)c[i] = a[i];//c数组用于下面原数组的赋值
    	sort(c+1,c+1+mx,cmp);
    	int l = 1,r = mx;
    	for(R int i = 1;i <= m;i++){
    		if(flag[i]>=b[i].pos)continue;
    		if(b[i].opt==1){
    			for(R int j = 0;b[i].pos-j>flag[i];j++){//从右端点开始赋值,一直到下一次操作的端点
    				a[b[i].pos-j] = c[l++];//从大的开始拿
    			}
    		}else{
    			for(R int j = 0;b[i].pos-j>flag[i];j++){
    				a[b[i].pos-j] = c[r--];//从小的开始拿
    			}
    		}
    	}
    	for(R int i = 1;i <= n;i++)printf("%d ",a[i]);
    	return 0;
    }
    
  • 相关阅读:
    ORACLE中dba,user,v$等开头的常用表和视图
    CentOS最基本的20个常用命令
    Spring IOC原理解读 面试必读
    Nginx Web服务应用
    Linux系统SSH免密登录
    Zabbix+Grafana打造高逼格监控系统
    Ansible入门
    你应该知道的 5 个 Docker 工具
    关于 Docker Hub 上不能注册 Docker ID 的问题
    Linux下终端录制工具-asciinema
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13802999.html
Copyright © 2020-2023  润新知