[NOIP2023] 双序列拓展
定义长度为 \(n\) 的序列 \(B\) 是长度为 \(m\) 的序列 \(A\) 的拓展,当且仅当存在长度为 \(m\) 的正整数序列 \(L\),使得将 \(a_i\) 替换成 \(l_i\) 个 \(a_i\) 后序列 \(A\) 与序列 \(B\) 相同。
给定长度为 \(n\) 的序列 \(X\) 和长度为 \(m\) 的序列 \(Y\)。判断是否能找到长度为 \(l=10^{100}\) 的两个序列 \(F\) 和 \(G\),使得 \(F\) 是 \(X\) 的拓展,\(G\) 是 \(Y\) 的拓展,且对于任意 \(i,j \in [1,l]\),\((f_i-g_i)(f_j-g_j)>0\) 成立。
\(q \leq 60\) 组数据,\(1 \leq n,m \leq 5 \times 10^5\)。
容易发现 \(x_1=f_1\),\(y_1=g_1\)。不妨钦定 \(f_1<g_1\),即 \(x_1<y_1\)。此时问题条件等价于对于所有 \(i\),都有 \(f_i<g_i\)。
我们考虑将 \(f_i>g_i\) 的条件转化为对序列 \(X\) 和 \(Y\) 的约束。不妨对下标进行匹配,则对于每组匹配的下标 \((i,j)\),都有 \(x_i<y_j\)。初始时匹配的下标为 \((1,1)\),最后匹配的下标为 \((n,m)\)。考虑若当前匹配的下标为 \((i,j)\),则下一步匹配的下标一定为 \((i+1,j)\),\((i,j+1)\) 或 \((i+1,j+1)\)。我们可以将其看成网格图,点 \((i,j)\) 能经过当且仅当 \(x_i<y_j\),判断是否存在从 \((1,1)\) 到 \((n,m)\) 的路径,每一步只能往下,往右或往右下走。
接下来进行观察:
性质 \(1\):若存在满足条件的路径,则一定存在一条从 \((1,1)\) 到 \((n,m)\) 的路径,每一步只能往下或往右走。
证明 \(1\):考虑若能够从 \((i,j)\) 到 \((i+1,j+1)\),则必有 \(x_i<y_j\) 且 \(x_{i+1}<y_{j+1}\)。此时不难发现 \(x_i<y_{j+1}\) 与 \(x_{i+1}<y_j\) 必然有至少一条成立。若否,此时有 \(x_i < y_j \leq x_{i+1} < y_{j+1} \leq x_i\),推出 \(x_i < x_i\),矛盾。则必然存在一条路径,只能往下或往右走。
发现没有思路,于是你打开了特殊性质:
保证 \(x_n\) 是 \(X\) 的唯一最小值,\(y_m\) 是 \(Y\) 的唯一最大值。
特殊性质给的很吓人,考虑这有什么用。首先我们发现,若某一行或某一列的格子全部无法经过,则必然无解。此时对应 \(x_{\max} \geq y_{\max}\) 或 \(x_{\min} \geq y_{min}\)。
此时我们必然有 \(x_{\max} < y_{\max}\) 且 \(x_{\min} < y_{\min}\)。这意味着 \(x_i < y_m\) 与 \(x_n < y_j\),则第 \(n\) 行和第 \(m\) 列的所有格子均可通过。所以,只要到达了第 \(n\) 行或第 \(m\) 列,就一定能到达终点。
接下来我们考虑递归下去。我们找到 \(x_1\) 到 \(x_{n-1}\) 的最小值 \(x_p\),以及 \(y_1\) 到 \(y_{m-1}\) 的最小值 \(y_q\)。若 \(x_p<y_q\),则对于 \(j \in [1,m-1]\),必有 \(x_p < y_j\),即第 \(p\) 行是可以通过的,问题缩小到 \(n=p\) 的情况。同理,找到 \(x_1\) 到 \(x_{n-1}\) 的最大值 \(x_r\),以及 \(y_1\) 到 \(y_{m-1}\) 的最大值 \(y_s\)。若 \(x_r < y_s\),则对于 \(i \in [1,n-1]\),必有 \(x_i < y_s\),问题缩小到 \(m=s\) 的情况。若两者都不成立,容易发现此时必有一行一列是不可通过的,\((1,1)\) 必然无法到达第 \(n\) 行或第 \(m\) 列。当递归到 \(n=1\) 或 \(m=1\) 时,此时必然有解。
考虑非特殊性质怎么做。特殊性质其实我们找到 \(X\) 的最小值 \(x_a\) 和 \(Y\) 的最大值 \(y_b\)。先特判 \(x_{\max} \geq y_{\max}\) 或 \(x_{\min} \geq y_{min}\),判断后第 \(a\) 行和第 \(b\) 列必然可以通过,按照上面的方法,对左上和右下两部分分别执行算法即可。
时间复杂度 \(O(q(n+m))\),可以通过。
#include<iostream>
#include<cstdio>
using namespace std;
int c,n,m,q,x[500010],y[500010],x_tmp[500010],y_tmp[500010];
int len_f,len_g,f[500010],g[500010];
int f_max_l[500010],f_max_r[500010],f_min_l[500010],f_min_r[500010];
int g_max_l[500010],g_max_r[500010],g_min_l[500010],g_min_r[500010];
bool check1(int x_pos,int y_pos){
if(x_pos==1 || y_pos==1){
return true;
}
int x_min_pos=f_min_l[x_pos-1],x_max_pos=f_max_l[x_pos-1],y_min_pos=g_min_l[y_pos-1],y_max_pos=g_max_l[y_pos-1];
if(f[x_min_pos]<g[y_min_pos]){
return check1(x_min_pos,y_pos);
}
else if(f[x_max_pos]<g[y_max_pos]){
return check1(x_pos,y_max_pos);
}
else{
return false;
}
}
bool check2(int x_pos,int y_pos){
if(x_pos==len_f || y_pos==len_g){
return true;
}
int x_min_pos=f_min_r[x_pos+1],x_max_pos=f_max_r[x_pos+1],y_min_pos=g_min_r[y_pos+1],y_max_pos=g_max_r[y_pos+1];
if(f[x_min_pos]<g[y_min_pos]){
return check2(x_min_pos,y_pos);
}
else if(f[x_max_pos]<g[y_max_pos]){
return check2(x_pos,y_max_pos);
}
else{
return false;
}
}
bool check(){
f_max_l[1]=f_min_l[1]=1;
for(int i=2;i<=len_f;i++){
if(f[i]<f[f_max_l[i-1]]){
f_max_l[i]=f_max_l[i-1];
}
else{
f_max_l[i]=i;
}
if(f[i]>f[f_min_l[i-1]]){
f_min_l[i]=f_min_l[i-1];
}
else{
f_min_l[i]=i;
}
}
f_max_r[len_f]=f_min_r[len_f]=len_f;
for(int i=len_f-1;i>=1;i--){
if(f[i]<f[f_max_r[i+1]]){
f_max_r[i]=f_max_r[i+1];
}
else{
f_max_r[i]=i;
}
if(f[i]>f[f_min_r[i+1]]){
f_min_r[i]=f_min_r[i+1];
}
else{
f_min_r[i]=i;
}
}
g_max_l[1]=g_min_l[1]=1;
for(int i=2;i<=len_g;i++){
if(g[i]<g[g_max_l[i-1]]){
g_max_l[i]=g_max_l[i-1];
}
else{
g_max_l[i]=i;
}
if(g[i]>g[g_min_l[i-1]]){
g_min_l[i]=g_min_l[i-1];
}
else{
g_min_l[i]=i;
}
}
g_max_r[len_g]=g_min_r[len_g]=len_g;
for(int i=len_g-1;i>=1;i--){
if(g[i]<g[g_max_r[i+1]]){
g_max_r[i]=g_max_r[i+1];
}
else{
g_max_r[i]=i;
}
if(g[i]>g[g_min_r[i+1]]){
g_min_r[i]=g_min_r[i+1];
}
else{
g_min_r[i]=i;
}
}
int x_min_pos=f_min_l[len_f],x_max_pos=f_max_l[len_f],y_min_pos=g_min_l[len_g],y_max_pos=g_max_l[len_g];
if(f[x_max_pos]>=g[y_max_pos] || f[x_min_pos]>=g[y_min_pos]){
return false;
}
else{
return check1(x_min_pos,y_max_pos) && check2(x_min_pos,y_max_pos);
}
}
void solve(){
len_f=n;
for(int i=1;i<=len_f;i++){
f[i]=x[i];
}
len_g=m;
for(int i=1;i<=len_g;i++){
g[i]=y[i];
}
if(check()){
printf("1");
return ;
}
len_f=m;
for(int i=1;i<=len_f;i++){
f[i]=y[i];
}
len_g=n;
for(int i=1;i<=len_g;i++){
g[i]=x[i];
}
if(check()){
printf("1");
return ;
}
printf("0");
}
int main(){
scanf("%d %d %d %d",&c,&n,&m,&q);
for(int i=1;i<=n;i++){
scanf("%d",&x[i]);
}
for(int i=1;i<=m;i++){
scanf("%d",&y[i]);
}
solve();
while(q--){
int kx,ky;
scanf("%d %d",&kx,&ky);
for(int i=1;i<=n;i++){
x_tmp[i]=x[i];
}
for(int i=1;i<=m;i++){
y_tmp[i]=y[i];
}
while(kx--){
int p,v;
scanf("%d %d",&p,&v);
x[p]=v;
}
while(ky--){
int p,v;
scanf("%d %d",&p,&v);
y[p]=v;
}
solve();
for(int i=1;i<=n;i++){
x[i]=x_tmp[i];
}
for(int i=1;i<=m;i++){
y[i]=y_tmp[i];
}
}
return 0;
}

浙公网安备 33010602011771号