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 【模板】最长公共子序列
也不给你用上图的朴素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 三元上升子序列
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]
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的长度。 TLE了,发现可以没必要枚举k,可以用val实时更新长度。 进一步发现f的第一维也是可以省略的。 LCIS 加上路径输出。#include272. 最长公共上升子序列
#include#include#includeLCIS
#include