zoukankan      html  css  js  c++  java
  • CSP-S 2021

    T1:
    考虑每次飞机获得的编号机场是固定的。
    而是否走上廊道只取决于其的编号机场小于廊道数。
    那么只要考虑计算编号。
    那么可以发现实际上一个二维偏序(mex)
    考虑一维排序,一维优先队列,二分BIT (mex)

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #define N 100005
    
    int n,m1,m2;
    
    struct P{int l,r,op;}e[N];
    
    bool cmp(P a,P b){return a.l < b.l;}
    bool operator < (P a,P b){return a.r > b.r;}
    
    int T[N];
    
    #define lowbit(x) (x & -x)
    
    inline void add(int x,int p){
    	for(int i = x;i <= N - 1;i += lowbit(i)){
    		T[i] += p;
    	}
    }
    
    inline int find(int x){
    	int ans = 0 ;
    	for(int i = x;i;i -= lowbit(i)){
    		ans += T[i];
    	}	
    	return ans;
    }
    
    int lasin[N],lasout[N];
    
    std::priority_queue<P>QWQ;
    #define mid ((l + r) >> 1)
    
    inline int mex(){
    	int l = 1,r = N;
    	int ans = 0;
    	while(l <= r){
    		if(find(mid) != mid)
    		ans = mid,r = mid - 1;
    		else
    		l = mid + 1;
    	}
    	return ans;
    }
    
    inline void del1(){
    	std::sort(e + 1,e + m1 + 1,cmp);
    	for(int i = 1;i <= m1;++i){
    		e[i].op = i;		
    		if(QWQ.size())
    		while(QWQ.size() && QWQ.top().r < e[i].l )
    		add(lasin[QWQ.top().op],-1),QWQ.pop();
    		lasin[i] = mex();
    		add(lasin[i],1);
    		QWQ.push(e[i]);
    	}
    	std::sort(lasin + 1,lasin + m1 + 1);	
    }
    
    inline void del2(){
    	for(int i = 1;i <= N;++i)
    	T[i] = 0;
    	while(QWQ.size())
    	QWQ.pop();
    	std::sort(e + 1,e + m2 + 1,cmp);
    	for(int i = 1;i <= m2;++i){
    		e[i].op = i;		
    		while(QWQ.size() && QWQ.top().r < e[i].l )
    		add(lasout[QWQ.top().op],-1),QWQ.pop();
    		lasout[i] = mex();
    		add(lasout[i],1);
    		QWQ.push(e[i]);
    	}
    	std::sort(lasout + 1,lasout + m2 + 1);
    }
    
    int ans;
    
    inline int Findin(int x){
    	int l = 0,r = m1;
    	int ans = 0;
    	while(l <= r){
    		if(lasin[mid] <= x)
    		ans = mid,l = mid + 1;
    		else
    		r = mid - 1;
    	}
    	return ans;	
    } 
    
    inline int Findout(int x){
    	int l = 0,r = m2;
    	int ans = 0;
    	while(l <= r){
    		if(lasout[mid] <= x)
    		ans = mid,l = mid + 1;
    		else
    		r = mid - 1;
    	}
    	return ans;	
    } 
    
    int main(){
    //	freopen("airport.in","r",stdin);
    //	freopen("airport.out","w",stdout);
    	scanf("%d%d%d",&n,&m1,&m2);
    	for(int i = 1;i <= m1;++i)
    	scanf("%d%d",&e[i].l,&e[i].r);
    	del1();
    	for(int i = 1;i <= m2;++i)
    	scanf("%d%d",&e[i].l,&e[i].r);	
    	del2();
    	for(int i = 0;i <= n;++i){
    		int x = i,y = n - i;
    		int fx = Findin(x);
    		int fy = Findout(y);
    		ans = std::max(fx + fy,ans);
    	}
    	std::cout<<ans<<std::endl;
    }
    

    T3
    考虑枚举第一次是(L,R)
    不妨设是 (L) ,那么取出第一位 (x) 以及和他颜色相同的另外一位 (y)
    那么显然 (y) 一定是最后一次操作的。
    那么可以发现 (y) 已经把序列划分开了,即下列的操作不可以跨越 (y) 这个位置。
    即下一次操作的 (y2) 就是倒数第二次做的,那么显然是在划分开的两个序列断点的一侧,否则不合法。
    考虑维护每次操作划分序列的左右断点,以及当前选到哪一个即可。

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 500005
    
    int T;
    int n;
    int a[N << 1];
    int pos[N];
    int flg;
    char ans[N];
    
    inline void dfs(int l,int r,int ql,int qr,int dep){
    	if(dep == n){
    		for(int i = 0;i < n;++i)
    		putchar(ans[i]);
    		for(int i = n - 1;i >= 0;--i){
    		int now = (ans[i] == 'L' ? -- l : ++ r);
    		int tmp = pos[a[now]] - now;
    		if(tmp == ql)
    		putchar('L'),++ql;
    		else
    		putchar('R'),--qr;
    		}
    		flg = 1;					
    		puts("");
    	}
    	int tl = pos[a[l]] - l,tr = pos[a[r]] - r;
    	if(tl == ql - 1 && ql - 1 >  l){ans[dep] = 'L';dfs(l + 1,r,ql - 1,qr,dep + 1);return ;}
    	else
    	if(tl == qr + 1 && qr + 1 <= r){ans[dep] = 'L';dfs(l + 1,r,ql,qr + 1,dep + 1);return ;}
    	if(tr == ql - 1 && ql - 1 >= l){ans[dep] = 'R';dfs(l,r - 1,ql - 1,qr,dep + 1);return ;}
    	else
    	if(tr == qr + 1 && qr + 1 <  r){ans[dep] = 'R';dfs(l,r - 1,ql,qr + 1,dep + 1);return ;}	
    }
    
    int main(){
    	freopen("palin.in","r",stdin);
    	freopen("palin.out","w",stdout);
    	scanf("%d",&T);
    	while(T -- ){
    		scanf("%d",&n);
    		for(int i = 1;i <= n;++i)
    		pos[i] = 0;
    		for(int i = 1;i <= n << 1;++i)
    		scanf("%d",&a[i]),pos[a[i]] += i;
    		int m = n << 1;
    		flg = 0;
    		ans[0] = 'L';
    		dfs(2,m,pos[a[1]] - 1,pos[a[1]] - 1,1);
    		if(flg)continue;
    		ans[0] = 'R';		
    		dfs(1,m - 1,pos[a[m]] - m,pos[a[m]] - m,1);
    		if(flg)continue;
    		puts("-1");
    	}
    }
    

    T2
    不说了吧。
    太痛苦了。
    我现在写都觉得痛苦。
    我再用记忆化搜索写区间dp我是傻逼我是.

    #include<iostream>
    #include<cstdio>
    #define ll long long 
    #define N 505
    #define mod ((ll)1e9 + 7)
    
    ll f[N][N];
    ll g[N][N];
    ll x[N][N];
    int nex[N];
    int n,k;
    char s[N];
    
    int main(){
    	scanf("%d%d",&n,&k);
    	scanf("%s",s + 1);
    	for(int l = 1;l <= n;++l){
    		if(s[l] != '?' && s[l] != '*')continue;
    		x[l][l] = 1;
    		for(int r = l + 1;r <= n;++r){
    			if(s[r] != '?' && s[r] != '*')break;
    			x[l][r] = 1;
    		}
    	}
    	for(int len = 2;len <= n;++len){
    		int r;
    		for(int l = 1;l + len - 1 <= n;++l){
    			r = l + len - 1;
    			f[l][r] = g[l][r] = 0;
    			if((s[l] != '(' && s[l] != '?') || (s[r] != ')' && s[r] != '?'))
    			continue;
    			if(l + 1 == r){
    				f[l][r] = (f[l][r] + 1) % mod;
    				continue;
    			}
    			if(len - 2 <= k && x[l + 1][r - 1])
    			f[l][r] = (f[l][r] + 1) % mod;
    			f[l][r] = (f[l][r] + f[l + 1][r - 1] + g[l + 1][r - 1]) % mod;
    			for(int li = l + 1;li <= std::min(r - 2,l + k);++li)
    			if(x[l + 1][li])
    			f[l][r] = (f[l][r] + f[li + 1][r - 1] + g[li + 1][r - 1]) % mod;
    			for(int ri = r - 1;ri >= std::max(l + 2,r - k);--ri)
    			if(x[ri][r - 1])
    			f[l][r] = (f[l][r] + f[l + 1][ri - 1] + g[l + 1][ri - 1]) % mod;
    			//(....)
    			int op = 0;
    			for(int i = l + 1;i <= r - 2;++i){
    				if(op <= i)op = i + 1;
    				while((s[op] == '*' || s[op] == '?') && op < r - 1)op ++ ;
    				nex[i] = std::min(i + k + 1,op);
    			}//del_longest_***
    			ll sum = 0;
    			for(int j = l + 2;j <= nex[l + 1];++j)
    			sum = (sum + f[j][r]) % mod;
    			g[l][r] = (g[l][r] + (f[l][l + 1] + g[l][l + 1]) % mod * sum % mod) % mod;
    			for(int i = l + 2;i <= r - 2;++i){
    				sum = (sum - f[i][r] + mod) % mod;
    				for(int j = nex[i - 1] + 1;j <= nex[i];++j)
    				sum = (sum + f[j][r]) % mod;
    				g[l][r] = (g[l][r] + (f[l][i] + g[l][i]) % mod * sum % mod) % mod;
    			}
    			//()....()
    //			std::cout<<l<<" "<<r<<" "<<f[l][r]<<" "<<g[l][r]<<std::endl;
    		}
    	}
    	std::cout<<(f[1][n] + g[1][n]) % mod<<std::endl;
    }
    
  • 相关阅读:
    封装LuaEngine
    Lua for循环
    lua 排序
    Lua中的数学库
    linux 常用指令
    lua table 遍历
    Charles——charles代理菜单proxy总结——端口转发
    Charles——charles代理菜单proxy总结—— 开始/暂停模拟慢网速—— stop/start throttling 和 throttling settings
    Charles——charles代理菜单proxy总结——代理设置proxy setting
    Charles——charles代理菜单proxy总结——SSL代理设置SSL Proxying Srtting
  • 原文地址:https://www.cnblogs.com/dixiao/p/15465919.html
Copyright © 2011-2022 走看看