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;
}