【二维树状数组】【CF10D】 LCIS
Description
给你两个串,求他们的最长公共上升子序列
Input
第一行是第一个串的长度\(n\)
第二行\(n\)个数代表第一个串
第三行是第二个串的长度\(m\)
第四行\(m\)个数代表第二个串
Output
输出最长子序列的长度以及方案
Hint
\(For~All:\)
\(0~\leq~n~\leq~500\)
Solutoin
先考虑朴素DP,可以设\(f_{i,j}\)代表第一个串选前\(i\)个,第二个串选前\(j\)个的答案,转移显然\(f_{i,j}=\max\{f_{k,h}\}+1\),其中\(k~<~i,j~<~h,A_i=B_j,A_k=B_h\)。复杂度为\(O(n^4)\),GG。
考虑把这个问题放到一个串上,问题变成了求一个串的LIS,我口胡了一个十分鬼畜的算法:读入离散化以后,设\(f_i\)为当前算到的以\(i\)这个数结尾的ans,注意这里\(i\)是代表的是一个位置的值而不是下标。于是当正着扫描的时候,转移显然\(f_i=\max\{f_j\}+1\),其中\(j~<~i\)。发现\(f_i\)是从\(f_j\)的前缀\(\max\)转移过来的。于是可以使用树状数组维护这个前缀\(\max\)。具体的,\(f_i=ask(i-1)+1\),然后在树状数组上修改\(i\)位置的\(f_i\)。
考虑一共枚举\(n\)个位置,树状数组复杂度是\(O(logn)\),总复杂度为\(O(nlogn)\)
在这里放上一个串的树状数组LIS代码
#include<cmath>
#include<cstdio>
#include<algorithm>
#define rg register
#define ci const int
#define cl const long long int
typedef long long int ll;
namespace IO {
char buf[300];
}
template <typename T>
inline void qr(T &x) {
rg char ch=getchar(),lst=' ';
while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst == '-') x=-x;
}
template <typename T>
inline void qw(T x,const char aft,const bool pt) {
if(x < 0) {putchar('-');x=-x;}
rg int top=0;
do {
IO::buf[++top]=x%10+'0';
} while(x/=10);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
template <typename T>
inline T mmax(const T a,const T b) {return a > b ? a : b;}
template <typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template <typename T>
inline T mabs(const T a) {return a < 0 ? -a : a;}
template <typename T>
inline void mswap(T &a,T &b) {
T _temp=a;a=b;b=_temp;
}
const int maxn = 100010;
int n;
int MU[maxn],tree[maxn],frog[maxn],temp[maxn];
int ask(int);
void init_hash();
void change(int,ci);
inline int lowbit(ci x) {return x&(-x);}
int main() {
qr(n);
for(rg int i=1;i<=n;++i) {qr(MU[i]);temp[i]=MU[i];}
init_hash();
for(rg int i=1;i<=n;++i) {
frog[MU[i]]=ask(MU[i]-1)+1;
change(MU[i],frog[MU[i]]);
}
qw(n-ask(n),'\n',true);
return 0;
}
void init_hash() {
std::sort(temp+1,temp+1+n);
int *ed=std::unique(temp+1,temp+1+n);
for(rg int i=1;i<=n;++i) MU[i]=std::lower_bound(temp+1,ed,MU[i])-temp;
}
int ask(int x) {
int _ans=0;
while(x) {
_ans=mmax(_ans,tree[x]);
x-=lowbit(x);
}
return _ans;
}
void change(int x,ci v) {
while(x <= n) {
tree[x]=mmax(tree[x],v);
x+=lowbit(x);
}
}
回到这个题,我们可以仿照一个串的方式,再加一个维度,设\(f_{i,j}\)第一个串算到当前以\(i\)这个数结尾,第二个串以第\(j\)个位置结尾的\(ans\)。注意这里\(i\)代表的A串的值,\(j\)代表的是\(b\)串的下标。于是转移显然\(f_{i,j}=\max\{f_{k,h}\}+1\),其中\(k~<~i,h<j\)。于是发现\(i,j\)由一个矩形的前缀最大值转移过来,可以用二维树状数组维护这个最大值。这样复杂度降为\(O(n^2log^2n)\),可以通过本题。
这里的一个姿势是二维树状数组,他可以维护一个矩形的二维前缀和或前缀最大值。查询代码为
Zay ask(ci x,ci y) {
rg Zay _ret;
for(rg int i=x;i;i-=lowbit(i)) {
for(rg int j=y;j;j-=lowbit(j)) {
_ret=mmax(_ret,tree[i][j]);
}
}
return _ret;
}
修改代码为
void add(ci x,ci y) {
Zay _tp=Zay(x,y);
for(rg int i=x;i<=tcnt;i+=lowbit(i)) {
for(rg int j=y;j<=tcnt;j+=lowbit(j)) {
tree[i][j]=mmax(tree[i][j],_tp);
}
}
}
更一般的,修改代码中_tp可以改为一个传进来的参数代表要修改位置的值。
于是这个题就完了。
Code
#include<cmath>
#include<cstdio>
#include<algorithm>
#define rg register
#define ci const int
#define cl const long long int
typedef long long int ll;
namespace IO {
char buf[300];
}
template <typename T>
inline void qr(T &x) {
rg char ch=getchar(),lst=' ';
while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst == '-') x=-x;
}
template <typename T>
inline void qw(T x,const char aft,const bool pt) {
if(x < 0) {putchar('-');x=-x;}
rg int top=0;
do {
IO::buf[++top]=x%10+'0';
} while(x/=10);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
template <typename T>
inline T mmax(const T &a,const T &b) {return a > b ? a : b;}
template <typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template <typename T>
inline T mabs(const T a) {return a < 0 ? -a : a;}
template <typename T>
inline void mswap(T &a,T &b) {
T _temp=a;a=b;b=_temp;
}
const int maxn = 1010;
const int maxd = 1010;
int n,m,tcnt;
int a[maxn],b[maxn],MU[maxd],frog[maxd][maxd],remap[maxd];
struct Zay {
int x,y;
inline bool operator<(const Zay &_others) const {
return frog[this->x][this->y] < frog[_others.x][_others.y];
}
inline bool operator>(const Zay &_others) const {
return frog[this->x][this->y] > frog[_others.x][_others.y];
}
Zay (ci _a=0,ci _b=0) {x=_a,y=_b;}
};
Zay tree[maxd][maxd],pre[maxn][maxn],ans;
Zay ask(ci,ci);
void init_hash();
void add(ci,ci);
void dfs(ci,ci);
inline int lowbit(ci x) {return x&(-x);}
int main() {
qr(n);
for(rg int i=1;i<=n;++i) {qr(a[i]);MU[++tcnt]=a[i];}
qr(m);
for(rg int i=1;i<=m;++i) {qr(b[i]);MU[++tcnt]=b[i];}
init_hash();
for(rg int i=1;i<=n;++i) {
for(rg int j=1;j<=m;++j) if(a[i] == b[j]) {
Zay _temp=ask(a[i]-1,j-1);
frog[a[i]][j]=frog[_temp.x][_temp.y]+1;
pre[a[i]][j]=_temp;
add(a[i],j);
ans=mmax(ans,(Zay){a[i],j});
}
}
qw(frog[ans.x][ans.y],'\n',true);
dfs(ans.x,ans.y);
return 0;
}
void init_hash() {
std::sort(MU+1,MU+1+tcnt);
int *ed=std::unique(MU+1,MU+1+tcnt);
rg int k;
for(rg int i=1;i<=n;++i) k=std::lower_bound(MU+1,ed,a[i])-MU,remap[k]=a[i],a[i]=k;
for(rg int i=1;i<=m;++i) k=std::lower_bound(MU+1,ed,b[i])-MU,remap[k]=b[i],b[i]=k;
}
Zay ask(ci x,ci y) {
rg Zay _ret;
for(rg int i=x;i;i-=lowbit(i)) {
for(rg int j=y;j;j-=lowbit(j)) {
_ret=mmax(_ret,tree[i][j]);
}
}
return _ret;
}
void add(ci x,ci y) {
Zay _tp=Zay(x,y);
for(rg int i=x;i<=tcnt;i+=lowbit(i)) {
for(rg int j=y;j<=tcnt;j+=lowbit(j)) {
tree[i][j]=mmax(tree[i][j],_tp);
}
}
}
void dfs(ci x,ci y) {
if(!y) return;
dfs(pre[x][y].x,pre[x][y].y);
qw(remap[b[y]],' ',true);
}
Summary
二维树状数组查询和修改的操作。
【二维树状数组】【CF10D】 LCIS的更多相关文章
- 二维树状数组 BZOJ 1452 [JSOI2009]Count
题目链接 裸二维树状数组 #include <bits/stdc++.h> const int N = 305; struct BIT_2D { int c[105][N][N], n, ...
- HDU1559 最大子矩阵 (二维树状数组)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1559 最大子矩阵 Time Limit: 30000/10000 MS (Java/Others) ...
- POJMatrix(二维树状数组)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 22058 Accepted: 8219 Descripti ...
- poj 1195:Mobile phones(二维树状数组,矩阵求和)
Mobile phones Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 14489 Accepted: 6735 De ...
- Codeforces Round #198 (Div. 1) D. Iahub and Xors 二维树状数组*
D. Iahub and Xors Iahub does not like background stories, so he'll tell you exactly what this prob ...
- POJ 2155 Matrix(二维树状数组+区间更新单点求和)
题意:给你一个n*n的全0矩阵,每次有两个操作: C x1 y1 x2 y2:将(x1,y1)到(x2,y2)的矩阵全部值求反 Q x y:求出(x,y)位置的值 树状数组标准是求单点更新区间求和,但 ...
- [poj2155]Matrix(二维树状数组)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 25004 Accepted: 9261 Descripti ...
- POJ 2155 Matrix (二维树状数组)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 17224 Accepted: 6460 Descripti ...
- [POJ2155]Matrix(二维树状数组)
题目:http://poj.org/problem?id=2155 中文题意: 给你一个初始全部为0的n*n矩阵,有如下操作 1.C x1 y1 x2 y2 把矩形(x1,y1,x2,y2)上的数全部 ...
随机推荐
- linux-ubuntu常用命令(深圳文鹏)
系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...
- POJ-3273(二分)
//题意:给出农夫在n天中每天的花费,要求把这n天分作m组, //每组的天数必然是连续的,要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值. //思路:看到各组最小和最大的,果断上 ...
- Struts2(一.基本介绍,环境搭建及需求分析)
Struts2框架开发 前言 开发工具:eclipse struts1:老项目使用较多,维护时需要用到 struts2:新项目使用较多 一.特点 1. 无侵入式设计 struts2 与 struts ...
- web _service 接口
1.WebService 就是 http请求 post接口 2.需要加 请求头信息 Content-Type: text/xml; 3.需要把占位符换成需要的字符串 webservice接口可以 ...
- CSP201604-2:俄罗斯方块
引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...
- js判断PC端 移动端 并跳转到对应页面
一.PC端跳转到移动端 html页面: <script>var webroot="/",catid="{$catid}",murl="m/ ...
- python编辑三级目录
一.需求分析 三级目录要能够实现以下要求: 显示根目录,任何子目录中都可以通过输入b字符来返回根目录 任何子目录中都可以通过输入q字符来返回上一级目录 主目录进入子目录后,系统能够打印子目录,根据指打 ...
- 第二次ScrumMeeting博客
第二次ScrumMeeting博客 本次会议于10月26日(四)22时整在3公寓725房间召开,持续15分钟. 与会人员:刘畅.方科栋.辛德泰.窦鑫泽.张安澜. 1. 每个人的工作(有Issue的内容 ...
- Java 通过先序中序序列生成二叉树
题目 二叉树的前序以及后续序列,以空格间隔每个元素,重构二叉树,最后输出二叉树的三种遍历方式的序列以验证. 输入: 1 2 3 4 5 6 7 8 9 10 3 2 5 4 1 7 8 6 10 9 ...
- fast-IO
代码: int Scan() //输入外挂 { ,ch,flag=; if((ch=getchar())=='-') flag=; ') res=ch-'; ') res=res*+ch-'; ret ...