• CF1685E The Ultimate LIS Problem 【贪心,AGC】


    给定长为 \(2n+1\) 的排列 \(p_1,\cdots,p_{2n+1}\)\(q\) 次操作,每次给出 \(u,v\),表示 \(\text{swap}(p_u,p_v)\) 然后求任意 \(k\in[0,2n]\) 使得 \(p_{k+1},\cdots,p_{2n+1},p_1,\cdots,p_k\) 的 LIS 长度 \(\le n\),需判断无解。

    \(n,q\le 10^5\)


    怎么判无解阿?就是说所有循环移位的 LIS 长度 \(\ge n+1\)

    一个括号序列的结论突然出现:令 \(b_i=[p_i>n+1]-[p_i<n+1]\),其包含 \(n\)\(1\)\(n\)\(-1\)\(1\)\(0\),存在一个循环移位满足所有前缀和 \(\ge 0\)。看看这个循环移位的 LIS,如果不包含 \(n+1\) 则是 \(x\)\(-1\) 接上 \(n+1-x\)\(1\),从而第 \(x\)\(-1\) 在第 \(x\)\(1\) 之前,矛盾了,所以 LIS 必定包含 \(n+1\),之前是 \(x\)\(-1\),之后是 \(n-x\)\(1\),又由前缀和 \(\ge 0\) 的结论知 \(n+1\) 之前也有 \(x\)\(1\),之后也有 \(n-x\)\(0\)

    这个结论启发我们看看 \(n+1\) 在开头和结尾的循环移位的 LIS,可以发现前缀和仍然 \(\ge 0\),所以 LIS 必定包含 \(n+1\),从而两个 LIS 分别为 \(n+1,\cdots,2n+1\)\(1,\cdots,n+1\),也就是说 \(n+1\) 在开头时 \(i\)\(n+1+i\) 都按顺序出现,且 \(n+1+i\)\(i\) 之前(\(i\in[1,n]\))。

    事实证明满足这个条件就无解了:对于位置 \(k+1\) 开头的循环移位,位置 \(k\) 之后 \(<n+1\) 的数然后 \(n+1\) 接着位置 \(k\) 之前 \(>n+1\) 的数就是长度 \(\ge n+1\) 的上升序列。

    这也推出了求解方法:看看 \(n+1\) 在开头的循环移位,

    • 若有前缀和 \(<0\),就输出任意一个所有前缀和 \(\ge 0\) 的循环移位;
    • \(i\) 不按顺序出现,就输出 \(n+1\) 结尾的循环移位;
    • \(n+1+i\) 不按顺序出现,就输出 \(n+1\) 开头的循环移位。

    维护逆排列 \(\text{pos}_i\),然后维护 \(\sum_{i=1}^n[\text{pos}_{i+1}<\text{pos}_i]+[\text{pos}_1<\text{pos}_{n+1}]\)\(\sum_{i=1}^n[\text{pos}_{n+i+1}<\text{pos}_{n+i}]+[\text{pos}_{n+1}<\text{pos}_{2n+1}]\),再用线段树维护前缀和最小值,直接模拟即可,时间复杂度 \(\mathcal O((n+q)\log n)\)

    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> pii;
    const int N = 200003, M = 1 << 19;
    int n, q, m, p[N], ps[N], seg[M], sm1, sm2;
    pii mn[M];
    int sgn(int x){return (x > n + 1) - (x <= n);}
    void pup(int x){
    	seg[x] = seg[x << 1] + seg[x << 1 | 1];
    	mn[x] = min(mn[x << 1], MP(mn[x << 1 | 1].fi + seg[x << 1], mn[x << 1 | 1].se));
    }
    void build(int x = 1, int L = 1, int R = m){
    	if(L == R){mn[x] = MP(seg[x] = sgn(p[L]), L); return;}
    	int md = L + R >> 1;
    	build(x << 1, L, md);
    	build(x << 1 | 1, md + 1, R);
    	pup(x);
    }
    void upd(int pos, int x = 1, int L = 1, int R = m){
    	if(L == R){mn[x] = MP(seg[x] = sgn(p[L]), L); return;}
    	int md = L + R >> 1;
    	if(pos <= md) upd(pos, x << 1, L, md);
    	else upd(pos, x << 1 | 1, md + 1, R);
    	pup(x);
    }
    int qry(int pos, int x = 1, int L = 1, int R = m){
    	if(L == R) return 0;
    	int md = L + R >> 1;
    	if(pos <= md) return qry(pos, x << 1, L, md);
    	return seg[x << 1] + qry(pos, x << 1 | 1, md + 1, R);
    }
    void work(int x, int val){
    	if(x <= n + 1){
    		int lst = x == 1 ? n + 1 : x - 1, nxt = x == n + 1 ? 1 : x + 1;
    		sm1 -= (ps[x] < ps[lst]) + (ps[nxt] < ps[x]);
    	}
    	if(x >= n + 1){
    		int lst = x == n + 1 ? m : x - 1, nxt = x == m ? n + 1 : x + 1;
    		sm2 -= (ps[x] < ps[lst]) + (ps[nxt] < ps[x]);
    	}
    	ps[x] = val;
    	if(x <= n + 1){
    		int lst = x == 1 ? n + 1 : x - 1, nxt = x == n + 1 ? 1 : x + 1;
    		sm1 += (ps[x] < ps[lst]) + (ps[nxt] < ps[x]);
    	}
    	if(x >= n + 1){
    		int lst = x == n + 1 ? m : x - 1, nxt = x == m ? n + 1 : x + 1;
    		sm2 += (ps[x] < ps[lst]) + (ps[nxt] < ps[x]);
    	}
    }
    int main(){
    	ios::sync_with_stdio(0);
    	cin >> n >> q; m = n * 2 + 1;
    	for(int i = 1;i <= m;++ i){cin >> p[i]; ps[p[i]] = i;}
    	for(int i = 1;i <= n;++ i){
    		sm1 += ps[i + 1] < ps[i];
    		sm2 += ps[n + i + 1] < ps[n + i];
    	}
    	sm1 += ps[1] < ps[n + 1];
    	sm2 += ps[n + 1] < ps[m];
    	build();
    	while(q --){
    		int x, y; cin >> x >> y;
    		work(p[x], y); work(p[y], x);
    		swap(p[x], p[y]); upd(x); upd(y);
    		printf("%d\n", mn[1].fi < qry(ps[n + 1]) ? mn[1].se % m : (sm1 != 1 ? ps[n + 1] % m : (sm2 != 1 ? ps[n + 1] - 1 : -1)));
    	}
    }
    
  • 相关阅读:
    牛客网在线编程:解救小易
    牛客网在线编程:身份证分组
    牛客网在线编程:优雅的点
    用FlexSlider制作支付宝2013版幻灯片演示插件
    Mysql Join语法解析与性能分析详解
    SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段
    jQuery 分页插件 jqPagination的使用
    Android图片异步加载之Android-Universal-Image-Loader
    C#随机函数random()典型用法集锦
    CSS自适应布局(左右固定 中间自适应或者右侧固定 左侧自适应)
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/16357395.html
Copyright © 2020-2023  润新知