给出两个长度为 n 的整数序列,求它们的最长公共子序列(LCS)的长度,保证第一个序列中所有元素都不重复。注意:第一个序列中的所有元素均不重复。
第二个序列中可能有重复元素。
一个序列中的某些元素可能不在另一个序列中出现。
输入格式
第一行包含一个整数 n。接下来两行,每行包含 n 个整数,表示一个整数序列。
输出格式
输出一个整数,表示最长公共子序列的长度。数据范围
1≤n≤106,
序列内元素取值范围 [1,106]。
在这里插入图片描述
定理:最长公共子序列转化成最长上升子序列,只需要其中任意一个序列数元素不重复。
/*最长公共子序列转化成上升子序列只需要任意一个序列不重复即可。
思路:转化为最长公共子序列,因为不重复,都有唯一一个对应的坐标q[i]
二分找出一个比x小的最大元素的下标,按照要求插入到它的后面。
思路
已知第一个序列元素唯一,第二个序列元素可能重复
-可得第二个序列元素在第一个序列中元素下标一定唯一不变。
·所以可以将两个数组最长公共子序列转化为最长上升子序列。子序列定义为:组成子序列元素在原数组的下标一定是严格单调递增的。
#include <bits/stdc++.h>
using namespace std;
const int N=1E6+10;
int a[N],idx[N],b[N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
idx[a[i]] = i;
}
int x;
for(int i =1;i<=n;i++){
scanf("%d",&x);
b[i] =idx[x];
}
vector<int>res;
for(int i=1;i<=n;i++)
{
if(b[i]==0) continue;
if(res.empty()||res.back()<b[i]) res.push_back(b[i]);
else {
int id =lower_bound(res.begin(),res.end(),b[i])-res.begin();
res[id] =b[i];
}
}
printf("%d",res.size());
return 0;
}
X星球居民小区的楼房全是一样的,并且按矩阵样式排列。
其楼房的编号为 1,2,3… 当排满一行时,从下一行相邻的楼往反方向排号。
比如:当小区排号宽度为 6 时,开始情形如下:
1 2 3 4 5 6 12 11 10 9 8 7 13 14 15 … 我们的问题是:已知了两个楼号 m 和
n,需要求出它们之间的最短移动距离(不能斜线方向移动)。
//将m和n分别映射从0开始 便于计算 行列 并且下标为奇数的时候要对列进行翻转
#include <bits/stdc++.h>
using namespace std;
int main(){
int w,n,m;
scanf("%d%d%d",&w,&m,&n);
m--; n--; //讲两个楼的行号和列号从下标为0开始映射 (便于计算楼层数)
int x1 = m/w; int x2 = n/w; //计算行号
int y1 = m%w; int y2 = n%w; //模w计算列号 下标从0开始
if(x1%2) y1 = w-1-y1; //如果列号为奇数就表示是从右往左 所以进行列号翻转
if(x2%2) y2 = w-1-y2; //如果列号为奇数就表示是从右往左 所以进行列号翻转
cout<<abs(x1-x2)+abs(y1-y2); //使用曼哈顿距离计算长度
}
小明知道这些日期都在1960年1月1日至2059年12月31日。
令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入格式 一个日期,格式是”AA/BB/CC”。
即每个’/’隔开的部分由两个 0-9 之间的数字(不一定相同)组成。
输出格式 输出若干个不相同的日期,每个日期一行,格式是”yyyy-MM-dd”。
多个日期按从早到晚排列。
数据范围 0≤A,B,C≤9 输入样例: 02/03/04 输出样例: 2002-03-04 2004-02-03 2004-03-02
**思路:**枚举区间年份中的日期,首先判断每个日期是否合法,如果合法的话就根据条件判断(格式为年月日、月日年、日月年 分别与输入的三个数字相等)就输出。
#include <bits/stdc++.h>
using namespace std;
int months[13] ={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check_valid(int year,int month,int day){
if(month==0 ||month>12) return false;
if(day==0) return false;
if(month!=2&&day>months[month]) return false;
else {
int leap = (year%4==0&&year%100!=0)||(year%400==0);
if(day>months[month]+leap) return false;
}
return true;
}
int main(){
int a,b,c;
scanf("%d/%d/%d",&a,&b,&c);
for(int date = 19600101;date <=20591213; date++){ //遍历区间年份 判断合法年份再进行判断
int year = date/10000, month = date%10000/100, day = date %100; //算出年月日
if(check_valid(year,month,day)){ //判断如果日期合法
if(year%100==a&&month==b&&day==c|| //年月日 、月日年 日月年
month ==a&&day==b&&year%100==c||
day ==a &&month ==b&&year%100==c
)
printf("%d-%02d-%02d\n",year,month,day);
}
}
return 0;
}
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。
其中每一行的格式是:
ts id 表示在 ts 时刻编号 id 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式 第一行包含三个整数 N,D,K。
以下 N 行每行一条日志,包含两个整数 ts 和 id。
输出格式 按从小到大的顺序输出热帖 id。
每个 id 占一行。
数据范围 1≤K≤N≤105, 0≤ts,id≤105, 1≤D≤10000
思路: 题目要求得到一段时间范围内的帖子点击数判断是否为热帖,那么我们只需要统计一段时间内的各个帖子的点赞数。那么我们可以遍历每个帖子并且用一个滑动区间来做累加 每次将本次时间的帖子数+1,然后维护区间判断这个区间内当前帖子是否为热帖。存储的话就可以用一个二元组来存储 日期和帖子 并以日期作为第一关键字排序 可以使用pair 默认为第一个关键字排序
#include <bits/stdc++.h>
#include<vector>
using namespace std;
typedef pair<int,int>PII; //时间和点赞数
const int N = 1e5+10,D=1e4+10;
vector<pair<int,int>>p;
#define x first
#define y second
int n,d,k;
int cnt[N];
bool st[N];
int main(){
scanf("%d%d%d",&n,&d,&k);
int t,id;
for(int i=0;i<n;i++){
scanf("%d%d",&t,&id);
p.push_back({t,id});
}
sort(p.begin(),p.end());
for(int i=0,j=0;i<n;i++){
// 需要先将后面的指针数据放进来
int ids = p[i].y; //取出热帖Id
cnt[ids]++; //帖子点击量+1
while(p[i].x-p[j].x>=d){ //缩进左指针到范围内
cnt[p[j].y]--; //左指针帖子点击量-1
j++;
}
if(cnt[ids]>=k) st[ids]=true; //如果右指针热帖大于热帖量 那么标记为热帖
}
for(int i=0;i<=N;i++) //遍历筛选出热帖
if(st[i])
cout<<i<<endl;
}