双序列拓展:很妙的特殊性质类 dp 题,由部分分引导向正解。

题意简化

你可以把序列 \(X\) 和序列 \(Y\) 中的每一个数复制若干倍并接到这个数后面,问能否构造出一种方案,使得两个序列长度相等且所有的 \(X_i>Y_i\) 或者 \(X_i<Y_i\)。有 \(60\) 次修改,每次修改都要输出答案。

观察

初看这题,只会打一个暴力匹配的暴搜。

然后忽然看到了这题的神秘性质,于是就把这条性质拆分成了两部分:

  • \(x_1 < y_1\)
  • \(x_n\) 是序列 \(X\) 唯一的一个最小值,\(y_m\) 是序列 \(Y\) 唯一的一个最大值。

第一条性质

我们观察每个数列的第一项有什么特别的,容易发现,无论后面的数怎么复制,两个数列的第一个数都一定是匹配上的。也就是说,\(x_1\) 与 \(y_1\) 的大小关系就决定了其他 \(x_i\) 与 \(y_i\) 的关系。

于是我们根据每个数列的第一个元素判断到底是 \(X_i>Y_i\) 还是 \(X_i<Y_i\) 就好了。

由此我们可以设计 dp:

\(dp_{i,j}\) 表示目前序列 \(X\) 匹配到第 \(i\) 个数,序列 \(Y\) 匹配到第 \(j\) 个数可不可行。

转移显然有三种:

\[dp_{i,j}=dp_{i-1,j} \bigvee dp_{i,j-1} \bigvee dp_{i-1,j-1}
\]

第二条性质

我们观察到这个方程很像方格取数,把他转化到方格上来。(这是本题思维难度最大的地方,要有抽象问题的能力)

一个方格 \((i,j)\) 能被走,当且仅当 \(x_i < y_j\)。(在 \(x_1<y_1\) 时)

这里借一张洛谷题解的图:

发现我们很快能标出所有能被走的点,并且对于第二条性质,如果这个序列要存在,第 \(n\) 个行和第 \(m\) 列的所有数都一定是红色的。这是有解的不充分必要条件。

为啥呢?因为第 \(n\) 个数是 \(X\) 里面的最小值,而如果连最小值都无法与 \(Y\) 中的某一个匹配,那么其他的自然也不可以了。这样就形成了一行或一列全为空的情况,显然是无法走过去的。最大值那个也同理。

那么接下来怎么求解呢?我们可以采用分支的思路,将 \(X\) 与 \(Y\) 的长度均减 \(1\),递归求解即可。(这是因为后面的情况如果合法,那么右下角的部分一定能走到,因为剩下的部分有解的条件是一个存在长条,长条和原来的十字架组成新的十字架,就保证了一定能走到原来的那个更大的十字架里)

正解

下面肯定要往最大值最小值上面去想了。假设当前 \(X\) 的最小值在 \(i\),\(Y\) 的最大值在 \(j\),那么只有第 \(i\) 行和第 \(j\) 列全部是可以走的,当前局面才可能有解。

因为行列交叉形成一个十字架,所以我们递归求解左上部分与右下部份的答案即可,两者都能有解最终才有解。

如下图:

具体实现上,我们分别维护 \(X\) 的前缀、后缀最小值、最大值的位置和 \(Y\) 的前缀、后缀最小值、最大值的位置即可。一共要维护 \(8\) 个,递归进行求解即可。

因为每次分治最多只会修改一个数,那么每行每列总共一定不会超过 \(n+m\) 次被递归到,所以时间复杂度为 \(O(q(n+m))\)。

代码

参考了很多洛谷题解的细节与马蜂,确实是最好写、最直观的一种维护方式了。

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
int n,m,a[500005],b[500005],pa[500005],va[500005],pb[500005],vb[500005];
struct node{
int mx,mn;
}prea[500005],preb[500005],sufa[500005],sufb[500005];
void init()
{
prea[1]={1,1};
for(int i=2;i<=n;i++)
{
prea[i]=prea[i-1];
if(a[prea[i].mx]<a[i])prea[i].mx=i;
if(a[prea[i].mn]>a[i])prea[i].mn=i;
}
preb[1]={1,1};
for(int i=2;i<=m;i++)
{
preb[i]=preb[i-1];
if(b[preb[i].mx]<b[i])preb[i].mx=i;
if(b[preb[i].mn]>b[i])preb[i].mn=i;
}
sufa[n]={n,n};
for(int i=n-1;i>=1;i--)
{
sufa[i]=sufa[i+1];
if(a[sufa[i].mx]<a[i])sufa[i].mx=i;
if(a[sufa[i].mn]>a[i])sufa[i].mn=i;
}
sufb[m]={m,m};
for(int i=m-1;i>=1;i--)
{
sufb[i]=sufb[i+1];
if(b[sufb[i].mx]<b[i])sufb[i].mx=i;
if(b[sufb[i].mn]>b[i])sufb[i].mn=i;
}
}
bool checkl(int x,int y)
{
if(x==1||y==1)return 1;
node nx=prea[x-1],ny=preb[y-1];
if(a[nx.mn]<b[ny.mn])return checkl(nx.mn,y);
if(a[nx.mx]<b[ny.mx])return checkl(x,ny.mx);
return 0;
}
bool checkr(int x,int y)
{
if(x==n||y==m)return 1;
node nx=sufa[x+1],ny=sufb[y+1];
if(a[nx.mn]<b[ny.mn])return checkr(nx.mn,y);
if(a[nx.mx]<b[ny.mx])return checkr(x,ny.mx);
return 0;
}
void solve()
{
bool swp=0;
if(a[1]==b[1])
{
cout<<0;
return;
}
if(a[1]>b[1])
{
swap(a,b);
swap(n,m);
swp=1;
}
init();
node x=prea[n],y=preb[m];
if(a[x.mn]>=b[y.mn]||a[x.mx]>=b[y.mx])
{
cout<<0;
if(swp)
{
swap(a,b);
swap(n,m);
}
return;
}
cout<<(checkl(x.mn,y.mx)&&checkr(x.mn,y.mx));
if(swp)
{
swap(a,b);
swap(n,m);
}
} int main()
{
//freopen("expand.in","r",stdin);
//freopen("expand.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int c,q;
cin>>c>>n>>m>>q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i];
solve();
while(q--)
{
int kx,ky;
cin>>kx>>ky;
for(int i=1;i<=kx;i++)
{
cin>>pa[i]>>va[i];
swap(a[pa[i]],va[i]);
}
for(int i=1;i<=ky;i++)
{
cin>>pb[i]>>vb[i];
swap(b[pb[i]],vb[i]);
}
solve();
for(int i=1;i<=kx;i++)
{
swap(a[pa[i]],va[i]);
}
for(int i=1;i<=ky;i++)
{
swap(b[pb[i]],vb[i]);
}
}
return 0;
}

Luogu P9870 NOIp2023 双序列拓展 题解 [ 紫 ] [ 动态规划 ] [ 分治 ] [ adhoc ]的更多相关文章

  1. 【luogu P2023 [AHOI2009]维护序列】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2023 把P3373改一改直接粘过来就A #include <iostream> #include ...

  2. 72. Edit Distance(困难,确实挺难的,但很经典,双序列DP问题)

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...

  3. 成对HMM(Pair HMMs)用于双序列比对--转载

    http://blog.163.com/bioinfor_cnu/blog/static/19446223720118205527863/ 所有文章:http://blog.163.com/bioin ...

  4. [Luogu 2023] AHOI2009 维护序列

    [Luogu 2023] AHOI2009 维护序列 恕我冒昧这和线段树模板二有个琴梨区别? #include <cstdio> int n,m; long long p; class S ...

  5. [Luogu 1963] NOI2009 变换序列

    [Luogu 1963] NOI2009 变换序列 先%Dalao's Blog 什么?二分图匹配?这个确定可以建图? 「没有建不成图的图论题,只有你想不出的建模方法.」 建图相当玄学,不过理解大约也 ...

  6. 洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)

    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1311990 原题地址:洛谷P1155 双栈排序 ...

  7. Luogu 2540 斗地主增强版(搜索,动态规划)

    Luogu 2540 斗地主增强版(搜索,动态规划) Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游 ...

  8. Luogu 2668 NOIP 2015 斗地主(搜索,动态规划)

    Luogu 2668 NOIP 2015 斗地主(搜索,动态规划) Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来 ...

  9. Luogu 1514 引水入城 (搜索,动态规划)

    Luogu 1514 引水入城 (搜索,动态规划) Description 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N行M列的矩形,如上图 ...

  10. 【luogu P4462 [CQOI2018]异或序列】 题解

    题目链接:https://www.luogu.org/problemnew/show/P4462 ax+ax-1+...+ay = cntx+cnty 这样把一段序列变成两段相加跑莫队. #inclu ...

随机推荐

  1. API 接口开发调试工具之ApiPost

    安装 ApiPost ApiPost 支持 Windows.Mac.Linux 平台,你可以通过这个链接下载软件安装包: https://www.apipost.cn/download.html?fr ...

  2. OAuth2 当前登录用户修改

    1.业务说明 有些情况下,我们希望用户登录后,可以修改用户的某些信息,比如修改当前的公司信息. 2.实现方法 @Resource TokenStore tokenStore; public JsonR ...

  3. Electron(1) - 快速入门

    1.前言 本节主要讲述Electron的环境搭建以及如何快速创建一个应用 官方文档 2.环境搭建 (1)安装node.js (2)创建项目目录,初始化配置文件 //进入项目目录 并在此目录打开cmd窗 ...

  4. 为什么你用的 MyBatis 慢?一行配置让它性能翻倍!

    为什么你用的 MyBatis 慢?一行配置让它性能翻倍! 在 Java 后端开发的江湖里,MyBatis 堪称一员大将,凭借着灵活的 SQL 编写.方便的数据库对接能力,深受广大开发者的喜爱.但不少小 ...

  5. ProcessExplorer 多功能任务管理器软件-中文绿色单文件版

    今天我和大家分享一款系统监控工具--ProcessExplorer.一个比Windows自带的任务管理器更强大的工具.感觉最实用的是他的搜索功能,可以搜到系统任务管理器里面无法显示的应用, 大家可以网 ...

  6. Flutter 错误The argument type 'Color' can't be assigned to the parameter type 'MaterialStateProperty<Color?>?'.dart(argument_type_not_assignable)

    MaterialStateProperty<Color?>?和Color 当为TextButton等button添加颜色时,使用ButtonStyle为其添加颜色 TextButton( ...

  7. 【C#】【FFmpeg】获取电脑可用音视频设备并输出到下拉列表框

    [重要]不要边看文本边操作,本文由错误纠正,先看完一遍再说. 要使用的FFmpeg命令 ffmpeg -list_devices true -f dshow -i dummy 会输出的信息 通过正则取 ...

  8. linux tc命令进行网络限速、丢包、延迟设置(简单使用)

    linux自带tc命令版本不是很低的linux系统都自带tc如果你的系统不带这个命令,建议使用类似括号中的命令进行安装 (yum -y install iproute) TC 中使用下列的缩写表示相应 ...

  9. Java 中的这个绝对值有点不绝对啊!

    现象 假如有如下代码定义了一个方法 test(),它入参可以任何一个 int 类型的整数,那么它输出结果可能是什么? public class Test { public static void te ...

  10. Qt音视频开发07-合并音视频文件

    一.前言 之前已经把音视频分开存储了对应的文件,因为这个需求特别少,当然确实有部分用户是需要把音视频分开存储,但是毕竟是很少数,绝大部分的用户都是音视频合并到一个MP4文件,所以如果要合并到一个文件, ...