zoukankan      html  css  js  c++  java
  • codeforces 1558 D. Top-Notch Insertions (线段树+组合)

    题目链接:http://codeforces.com/contest/1558/problem/D

    如果没有插入的条件限制,那么对于所有元素都有 (a[i] <= a[i+1])

    每次插入相当于确定了一个小于关系,将 (x) 位置的元素插入到 (y) 位置,相当于 (a[x] < a[y])

    所以假设我们已经知道有 (c) 个 ‘(<)’ 关系,设排列后的序列为 (b),则有 (c) 个位置满足 (b[i]<b[i+1]),有 (n-1-c) 个位置满足 (b[i]<=b[i+1])(其中每个位置是什么关系已知),求有多少种序列 (b)

    答案为 (C_{2*n-1-c}^n),考虑对于 (n-1-c) 个满足相等关系的位置,将 (b[i+1],dots,b[n]) 这些元素全部 (+1),那么最大可能的元素为 (n+n-1-c),也即这一序列与在 (2*n-1-c) 的排列中选出 (n) 个数构成了双射

    如果将插入操作顺序反过来,逆向操作,那么每次插入的位置 (y) 的意义就是当前所有未填位置中第 (y) 大的位置 (p)(初始未填位置为 (1)(n)),而若当前第 (y+1) 大位置为 (q),那么 (p<q),如果没有其他元素 (w)(q) 满足 (w<q),则 (c++),否则 (c) 不变,(w)(p) 满足 (w<=p),找到未被选择的第 (k) 个位置可以使用线段树

    题目中说明不保证所有数据中 (n) 的和的范围,那么考虑到每次最多操作 (m) 次,记录操作的位置,最后将操作撤回即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 200010;
    const int M = 998244353;
    
    int T, n, m, c;
    int l[maxn], r[maxn], vis[maxn];
    
    int fac[2*maxn], ifac[2*maxn];
    
    struct Node{
    	int sum;
    }t[maxn<<2];
    
    void pushup(int i){
    	t[i].sum = t[i<<1].sum + t[i<<1|1].sum; 
    }
    
    void build(int i, int l, int r){
    	if(l == r) {
    		t[i].sum = 1;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(i<<1, l, mid); build(i<<1|1, mid + 1, r);
    	pushup(i);
    }
    
    void modify(int i, int p, int v, int l, int r){
    	if(l == r){
    		t[i].sum = v;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(p <= mid) modify(i<<1, p, v, l, mid);
    	else modify(i<<1|1, p, v, mid + 1, r);
    	pushup(i);
    }
    
    int query(int i, int k, int l, int r){
    	if(l == r){
    		return l;
    	}
    	int mid = (l + r) >> 1;
    	if(t[i<<1].sum >= k) return query(i<<1, k, l, mid);
    	else return query(i<<1|1, k-t[i<<1].sum, mid + 1, r);
    }
    
    int qsm(int i, int po){
    	int res = 1;
    	while(po){
    		if(po & 1) res = 1ll * res * i % M;
    		po >>= 1;
    		i = 1ll * i * i % M;
    	}
    	return res;
    }
    
    vector<int> vp;
    vector<int> vq;
    
    int C(int x, int y){
    	return 1ll * fac[x] * ifac[y] % M * ifac[x-y] % M;
    }
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	T = read();
    	
    	fac[0] = 1;
    	for(int i = 1 ; i <= 400000 ; ++i) fac[i] = 1ll * fac[i-1] * i % M;
    	ifac[400000] = qsm(fac[400000], M - 2);
    	for(int i = 399999 ; i >= 0 ; --i) ifac[i] = 1ll * ifac[i+1] * (i+1) % M;
    	
    	build(1, 1, 200000);
    	
    	
    	while(T--){
    		vp.clear(); vq.clear();
    		c = 0;
    		n = read(), m = read();
    		for(int i = 1 ; i <= m ; ++i){
    			l[i] = read(), r[i] = read();
    		}
    		
    		for(int i = m ; i >= 1 ; --i){
    			int p = query(1, r[i], 1, 200000);
    			int q = query(1, r[i]+1, 1, 200000);
    			
    			vp.push_back(p);
    			vq.push_back(q);
    			modify(1, p, 0, 1, 200000);
    			if(!vis[q]) {
    				++c;
    				vis[q]++;
    			}
    		}
    		
    		printf("%d
    ", C(2*n-c-1, n));
    		
    		for(auto u : vp) modify(1, u, 1, 1, 200000);
    		for(auto u : vq) vis[u] = 0; 
    	}
    	return 0;
    }
    
  • 相关阅读:
    学习 iOS多线程开发 Demo示意
    python(数字Number)
    python(元组)
    python(列表)
    python(一)
    APP自动化测试框架搭建(转载)
    Appium真机运行Device Name获取方法
    关于android sdk manager在下载包时没有android intel x86 atom system image等项
    adb shell命令查看当前与用户交互的activity
    SDK更新
  • 原文地址:https://www.cnblogs.com/tuchen/p/15191914.html
Copyright © 2011-2022 走看看