LIS.LCS.LCIS相关问题
创始人
2024-01-22 05:36:12
0

文章目录

  • P1020 [NOIP1999 普及组] 导弹拦截
  • P1439 【模板】最长公共子序列
  • P1637 三元上升子序列
  • 272. 最长公共上升子序列
  • LCIS

在这里插入图片描述

P1020 [NOIP1999 普及组] 导弹拦截

P1020 [NOIP1999 普及组] 导弹拦截

导弹拦截应该是接触DP的第一题(只不过洛谷上的数据加强了,按照上图的O(N2)O(N^2)O(N2)做法过不去QAQ可以改用二分。

Dilworth定理:偏序集能划分成的最少的全序集个数等于最大反链的元素个数

把一个数列划分成最少的最长不升子序列的数目就等于这个数列的最长上升子序列的长度(LIS)

#include 
using namespace std;
int a[100010],LDS[100010],LIS[100010];
int main()
{int x,i=0,len=1;while(~scanf("%d",&x))a[i++]=x;LDS[0]=a[0];for(int j=1;jif(a[j]<=LDS[len-1])LDS[len++]=a[j];else{int l=0,r=len;while(lint mid=(l+r)>>1;if(a[j]>LDS[mid]) r=mid;else l=mid+1;}LDS[l]=a[j];}}cout<if(a[j]>LIS[len2-1])LIS[len2++]=a[j];else{int l=0,r=len2;while(lint mid=(l+r)>>1;if(a[j]<=LIS[mid]) r=mid;else l=mid+1;}LIS[l]=a[j];}}cout<

P1439 【模板】最长公共子序列

P1439 【模板】最长公共子序列

也不给你用上图的朴素DP过去(O(N2)O(N^2)O(N2))www

for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){dp[i][j]=max(dp[i-1][j],dp[i][j-1]);if(a1[i]==a2[j])dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);}cout<

但本题数据有个明显的特征即两个序列都是全排列,也就是说我们可以重新构造一种映射关系。

#include 
using namespace std;
int a[100010],b[100010],LIS[100010];
int main()
{int n,i;cin>>n;//由于a b 中元素完全相同,只是顺序不同,可以利用映射关系,将a映射成一个单调递增序列 for(int i=1;i<=n;i++){int x;scanf("%d",&x);a[x]=i;}//相应地,由a给出的映射关系,可将b构造成一个新的序列 for(int i=1;i<=n;i++){int y;scanf("%d",&y);b[i]=a[y];}// 两个序列的子序列,一定是a的子序列。而a本身就是单调递增的。因此这个子序列是单调递增的。//换句话说,只要这个子序列在b中单调递增,它就是a的子序列//哪个最长呢?当然是b的LIS最长。下用二分+贪心求b的LIS即可 LIS[1]=b[1];int len2=1;for(int j=2;j<=n;j++){if(b[j]>LIS[len2])LIS[++len2]=b[j];//如果此时检索到的数比LIS的最后一个数(也即最大的数)大,直接插到LIS尾部 else//否则,在LIS前面的数中二分查找合适的位置进行替换 {int l=1,r=len2;while(lint mid=(l+r)>>1;if(b[j]<=LIS[mid]) r=mid;else l=mid+1;}LIS[l]=b[j];}}cout<

P1637 三元上升子序列


P1637 三元上升子序列
UVA12983 The Battle of Chibi

给定一个长度为n的序列,求其包含的m元单调上升子序列个数。
见求LIS思DP。导弹拦截那种题,开f[结尾编号]=序列长度,信息量不够,考虑定义f[序列长度][结尾编号] =序列个数。

状态转移:f[i][j]=∑f[i−1][k],1<=k

这样做的时间复杂度为O(n2∗m)O(n^2*m)O(n2∗m)

得想办法在更短时间内统计出∑f[i−1][k]\sum f[i-1][k]∑f[i−1][k],树状数组或者线段树都可以实现在O(logn)O(log n)O(logn)内的区间统计。

先离散化,将a[]的分布集中起来,以a[k]为下标储存f[i-1][k]的值。

此时针对状态转移方程写两层循环:外层循环枚举长度,每次枚举到一个长度都重置一下树状数组c[]。{内层枚举序列结尾坐标,此前已将f[i-1][k]增加到树状数组中,此时只需用树状数求和即可。然后把f[i-1][j]加到树状数组中,这个值只会更新到比a[j]大的数(对应状态转移方程里的a[k]

#include
using namespace std;
#define ll long long
const int N=30010;
ll n,f[4][N],a[N],b[N],c[N],ans;ll lowbit(ll x) { return x&(-x);}void update(ll p,ll v)
{for(int i=p;i<=n;i+=lowbit(i))c[i]+=v;
} ll ask(int p)
{ll sum=0;for(int i=p;i;i-=lowbit(i))sum+=c[i];return sum;
}int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i];sort(b+1,b+n+1);unique(b+1,b+n+1)-(b+1);for(int i=1;i<=n;i++){a[i]=lower_bound(b+1,b+n+1,a[i])-b;//二分查找在数组中的位置f[1][i]=1;//初始化:长度唯一,本身为结尾}//离散化结束,初始化结束,准备工作完成for(int i=2;i<=3;i++)//枚举长度{memset(c,0,sizeof(c));//重置树状数组for(int j=1;j<=n;j++){f[i][j]=ask(a[j]-1);//求和update(a[j],f[i-1][j]);//更新}}for(int i=1;i<=n;i++)ans+=f[3][i];cout<

272. 最长公共上升子序列

272. 最长公共上升子序列

定义f[i][j]f[i][j]f[i][j]:a[1]−a[i],b[1]−b[j]a[1]-a[i],b[1]-b[j]a[1]−a[i],b[1]−b[j]可以构成的以b[j]b[j]b[j]结尾的LCIS的长度。

#include
using namespace std;
const int N=3010;
int f[N][N];
int n,a[N],b[N];
int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)scanf("%d",&b[i]);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){f[i][j]=f[i-1][j];if(a[i]==b[j]){int maxv=1;for (int k=1;kb[k]) maxv=max(maxv, f[i - 1][k] + 1);f[i][j]=max(f[i][j], maxv);}}int ans=0;for(int j=1;j<=n;j++)ans=max(ans,f[n][j]);cout<

TLE了,发现可以没必要枚举k,可以用val实时更新长度。

#include
using namespace std;
const int N=3010;
int f[N][N];//a1~ai,b1~bj可以构成的以bj结尾的LCIS的长度
int n,a[N],b[N],ans=0,m;
int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)scanf("%d",&b[i]);for(int i=1;i<=n;i++){int val=0;//(i,0)的LCIS长度//i固定,b1->bn时LCIS长度一定是单调递增的for(int j=1;j<=n;j++){if(a[i]==b[j]) f[i][j]=val+1;//遍历到一个ai、bj相同的位置,长度++else f[i][j]=f[i-1][j];//不相等,直接继承(i-1,j)的长度if(b[j]a[i])一定不会影响到LCIS的长度}}for(int j=1;j<=n;j++)//找出所有以bj结尾的LCIS中长度最大的ans=max(ans,f[n][j]);cout<

进一步发现f的第一维也是可以省略的。

#include
using namespace std;
const int N=3010;
int f[N];//a1~ai,b1~bj可以构成的以bj结尾的LCIS的长度
int n,a[N],b[N],ans=0,m;
int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)scanf("%d",&b[i]);for(int i=1;i<=n;i++){int val=0;//(i,0)的LCIS长度//i固定,b1->bn时LCIS长度一定是单调递增的for(int j=1;j<=n;j++){if(a[i]==b[j]) f[j]=val+1;//遍历到一个ai、bj相同的位置,长度++if(b[j]a[i])一定不会影响到LCIS的长度}}for(int j=1;j<=n;j++)//找出所有以bj结尾的LCIS中长度最大的ans=max(ans,f[j]);cout<

LCIS

LCIS

加上路径输出。

#include
using namespace std;
const int N=3010;
int f[N];//a1~ai,b1~bj可以构成的以bj结尾的LCIS的长度
int n,a[N],b[N],ans[N],m,scheme[N],p;
int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%d",&a[i]);cin>>m;for(int i=1;i<=m;i++)scanf("%d",&b[i]);for(int i=1;i<=n;i++){int id=0;//i固定,b1->bn时LCIS长度一定是单调递增的for(int j=1;j<=m;j++){if(a[i]==b[j]) f[j]=f[id]+1,scheme[j]=id;//遍历到一个ai、bj相同的位置,长度++,记录下j前面一个位置是id if(b[j]f[p]) p=i;//找出所有以bj结尾的LCIS中长度最大的printf("%d\n",f[p]);int top=0;while(f[p]--) {ans[++top]=b[p];id=scheme[p];//从后往前倒出来 }for(int i=top;i;i--)printf("%d ",ans[i]);//输出方案前需要记录return 0;
}

相关内容

热门资讯

关于调整山西省2025年老旧营... 为积极稳妥开展山西省老旧营运货车报废更新工作,现就调整我省2025年老旧营运货车报废更新补贴政策实施...
全国首个航标碰撞争议“调解-仲... 11月21日,在厦门自贸片区管委会的推动下,东海航海保障中心厦门航标处、厦门海事局、厦门仲裁委员会等...
原创 日... 日方连出三招,军事政策或许将会有重大转向。与此同时,不到48小时,中方直接连发三道质问。日方到底连出...
厦门市市场监管局推进“免申即享... “以前申请要转两趟公交,材料没带齐还得跑第二趟。现在120元污水处理费直接退款到账,政府考虑得很周全...
浙江尖峰集团股份有限公司 关于... 证券代码:600668 证券简称:尖峰集团 编号:临2025-064 浙江尖峰集团股份有限公司 关于...
四川宜宾一小区发生入室盗窃案 ... 封面新闻记者 伍雪梅 11月21日,记者从四川省宜宾市公安局翠屏区分局获悉,11月19日,翠屏区西郊...
【深圳特区报】十五运会组委会在... 11月21日,十五运会组委会在深圳市民中心总结本届赛事相关情况。十五运会组委会副主任、国家体育总局副...
特斯拉因致命车祸在美被起诉,车... 据报道,特斯拉(TSLA.O)在华盛顿州被起诉,此前发生的一起致命火灾事故导致一人死亡、一人重伤,据...
里德·谢泼德:从犹豫到自信,火... 在休斯顿火箭队与孟菲斯灰熊队的比赛中,里德·谢泼德经历了一次关键的心理考验。在比赛的紧张时刻,谢泼德...