小h最近看了谍战电影,对里面消息的加密方式很感兴趣,他决定和朋友试一试,小h给朋友两个序列,两个序列的最长公共单调递增子序列就是要传递的消息,有时候序列太长了,小h的朋友找不出来,所以他找到了你
第一个数字n表示序列长度
后面两行每行n个数字表示小h给出的两个序列
(n<=1000)
输出需要传递的原序列的长度
3
1 2 3
3 1 2
2
需要传递的是1 2这个子序列
这是公共递增子序列问题,最朴素的算法是O(n^3) dp[i][j]表示以b[j]结尾的公共子序列
如果a[i]==b[j]那答案就是a[i]和b[j]匹配接在dp[i-1][k]后(k小于j且b[k]
至于为什么是dp[i-1]呢,因为dp[i-1][k]必定比dp[i-x][k](x>1)更优
如果a[i]!=b[j]那答案就是dp[i-1][j],不要a[i]嘛
PS:当然n的范围是1000的话n3就是109肯定会超时的
#include
#define ll long long
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
int a[1005],b[1005],dp[1005][1005];
int main()
{
int n,m;
scanf("%d",&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 num=0;
for(int j=1;j<=n;++j){
if(a[i]==b[j]){
dp[i][j]=1;
for(int k=1;k<j;++k){
if(b[k]<b[j]&&dp[i-1][k]+1>dp[i][j]){
dp[i][j]=dp[i-1][k]+1;
}
}
}else{
dp[i][j]=dp[i-1][j];
}
}
}
int ans=0;
for(int i=1;i<=n;++i)ans=max(ans,dp[n][i]);
printf("%d\n",ans);
return 0;
}
n^3会超时那考虑优化一维前两维很明显是不能优化的,必须枚举所有情况,那只能从第三维入手
枚举第二维的时候维护最长的能接在b[j]前的不就可以了
用一个临时数组num存比在b[j]前比b[j]小的最长公共递增子序列长度
那第三维就可以省略了。
当然因为dp的时候状态至于前一列状态有关,甚至可以将dp数组转成一维,不过意义不大,在这就不写了
#include
#define ll long long
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int a[1005],b[1005],dp[1005][1005];
int main()
{
int n,m;
scanf("%d",&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 num=0;
for(int j=1;j<=n;++j){
dp[i][j]=dp[i-1][j];
if(a[i]>b[j]&&num<dp[i-1][j])num=dp[i-1][j];//b[k]比a[i]小就取dp[i-1][k]的最大值
if(a[i]==b[j])dp[i][j]=num+1;//当a[i]==b[j],num取的是比a[i]小的b[k]那自然b[j]>b[k]
}
}
int ans=0;
for(int i=1;i<=n;++i)ans=max(ans,dp[n][i]);
printf("%d\n",ans);
return 0;
}
有一个初始长度为0的数列,三种操作
1.将某一个元素插入
2.将某一个元素删除
3.查询当前状态
第一个数字m表示有m个操作
后面m行表示m个操作
每行输入一个数字op
如果op=1表示第一个操作,后面接着两个数字a,b表示在第a个位置插入b(a以及a后的数字后移)
如果op=2表示第二个操作,后面接着一个数字a表示删除第a数字
如果op=3表示第三个操作,查询当前数列的状态
(m<=1000,操作保证合法)
对于每一个op=3输出当前数列的状态
3
1 1 3
1 2 4
3
3 4
这题本来是作为链表题来出的,后面改了数据范围,那用数组暴力模拟也可以过
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int ans[maxn];
int main()
{
int n,op,now=0,a,b;
scanf("%d",&n);
while(n--){
scanf("%d",&op);
if(op==1){
scanf("%d %d",&a,&b);
++now;
for(int i=now;i>a;--i){
//插入位置到最后一个元素右移
ans[i]=ans[i-1];
}
ans[a]=b;
}else if(op==2){
scanf("%d",&a);
for(int i=a;i<now;++i){
//删除位置后一个元素到最后一个元素左移
ans[i]=ans[i+1];
}
--now;
}else{
for(int i=1;i<=now;++i){
printf("%d%c",ans[i],i==now?'\n':' ');
}
}
}
return 0;
}
#include
#define ll long long
using namespace std;
const int maxn=2e5+5;
const int inf=0x3f3f3f3f;
struct node{
//链表节点结构体
int v;
node *nex;
};
void cout_(node *head){
//循环输出链表的值
node *now=head->nex;//第一个元素是head的nex(head是不存东西的)
while(now!=NULL){
//循环输出,直到链表末尾
printf("%d",now->v);
now=now->nex;
if(now!=NULL){
printf(" ");
}
}
printf("\n");
}
int main()
{
int n,m,op,a,b;
node *head=(node*)malloc(sizeof(node));//给头结点指针分配内存
head->nex=NULL;
scanf("%d",&m);
for(int i=1;i<=m;++i){
scanf("%d",&op);
if(op==1){
scanf("%d %d",&a,&b);
a--;
node *now=head;
while(a--){
//找到插入位置的前一个元素
now=now->nex;
}
node *ne=(node*)malloc(sizeof(node));
//链表插入
ne->v=b;
ne->nex=now->nex;
now->nex=ne;
}else if(op==2){
scanf("%d",&a);
a--;
node *now=head;
while(a--){
//找到删除位置的前一个元素
now=now->nex;
}
//链表删除
node *p=now->nex;
now->nex=p->nex;
free(p);
}else{
//输出链表数据
cout_(head);
}
}
return 0;
}
现有一个正整数,希望去掉这个数中某一个数字之后可以得到一个回文素数。 单组输入。输入一行,包含两个正整数N和M,1<=N 输出在N和M之间(包含N和M)满足要求的数的个数。 在110和120之间存在10个满足要求的数,分别是110、111、112、113、114、115、116、117、118和119,它们去掉最后一位数都可以得到一个回文素数11。 暴力枚举区间[n,m],枚举去掉每一位的数字,判断回文和素数 这6种形式,+0的可以被6整除,+2,+4的可以被2整除,+3的可以被3整除 求以下数列的和: 每组数据一个输入,每个输入一行,输入n。(n<=100) 输出数列前n项的和,结果四舍五入保留四位小数。 由最后两项可以知道,数列是 所以直接计算f(n)将中间答案累加就可以了 牛牛总是睡过头,所以他定了很多闹钟,只有在闹钟响的时候他才会醒过来并且决定起不起床。从他起床算起他需要X分钟到达教室,上课时间为当天的A时B分,请问他最晚可以什么时间起床? 每个输入包含一个测试用例。 循环判断最大的小于最迟起床时间的时间 在R星球有一类昆虫它是可以无性繁殖的,身为昆虫调查员的你接到了命令前往R星球去调查昆虫的繁殖情况 第一行 一段序列,代表昆虫的序号。每个昆虫带有两个子代,若没有子代的用-1代替。(如序列:1 2 -1 -1 3 -1 -1,表示1号有2,3两个子代而2,3没有子代,类似于二叉树的先序遍历) 输出一行,代表病毒昆虫的公共父辈编号 最近公共祖先问题(LCA) 容易发现上移过程是一步步的,很憨,那可以考虑多跨几步嘛 小明的弟弟刚刚学会了写英语的一(one)、二(two)、三(three)和四(four)。 他在纸上写了一个单词,这个单词是one、two、three和four中的某一个。已知单词最多只有一个字母写错,但是单词的长度肯定不会错。 你能认出他写的是哪个单词吗? 单组输入。 输入占1行,对应一个单词。单词长度正确,且最多只有一个字母写错。所有字母都是小写字母,且输入保证只有一种理解方式。 输出一行,即该单词对应的阿拉伯数字。 先判断长度,如果是长度是5那就是3如果长度是4那就是4 小虫虫由于出来找食物飞走了,小红红回到学校之后发现虫虫不见了,好在他在虫虫的身上装了定位。小红红跟着定位来到了一个迷宫,这个迷宫很复杂,几乎每条道路都是交错的,为了能快的找到虫虫,你能帮助小红红判断该路径是否存在回路嘛? 输入的第一行包含一个整数n,表示有n个节点。n不超过50 若读入的有向图含有回路,输入"can not find the bug" 按题目要求进行拓扑排序…
回文素数是指一个素数同时还是一个回文数(回文数即从左到右和从右到左均一样的数,例如12321)。【注意:一位数也被认为是回文数】
输入两个正整数N和M,满足N输入
输出
样例输入
110 120
样例输出
10
提示
思路
下面的代码用了6素数法(当然普通的也可以)
就是素数都在6的左右两边,所以只需要判断能否被6左右两边的数字整除就可以了
证明:
所有的数字可以写成6*k+0,6*k+1,6*k+2,6*k+3,6*k+4,6*k+5
那就只剩下+1和+5的
+1的在6的倍数的右边,+5的也就是-1,在6的倍数的左边代码
#include
问题 D: 数列求和
题目描述
f(n)=1/5-1/10+1/15-1/20+1/25-......+1/(5*(2*n-1))-1/(5*2*n)。
输入
输出
样例输入
1
样例输出
0.1000
思路
(1/5-1/10)+(1/15-1/20)+...+(1/(5*(2*n-1))-1/(5*2*n))
#include
问题 E: 牛牛的闹钟
题目描述
输入
每个测试用例的第一行包含一个正整数,表示闹钟的数量N(N<=100)。
接下来的N行每行包含两个整数,表示这个闹钟响起的时间为Hi(0<=A<24)时Mi(0<=B<60)分。
接下来的一行包含一个整数,表示从起床算起他需要X(0<=X<=100)分钟到达教室。
接下来的一行包含两个整数,表示上课时间为A(0<=A<24)时B(0<=B<60)分。
数据保证至少有一个闹钟可以让牛牛及时到达教室。输出
输出两个整数表示牛牛最晚起床时间。
样例输入
3
5 0
6 0
7 0
59
6 59
样例输出
6 0
思路
#include
问题 F: 繁殖
题目描述
经过一系列的调查,你发现该种昆虫一生最多可以繁殖出两个子代。现在你发现了这种昆虫身上可能会带有一种病毒,上级已经给你发来通知,告诉你了两只带有该病毒昆虫的编号。
为了快速找出这种病毒你必须找到这两只昆虫的最近公共父辈(不会存在两只昆虫出现相同编号)。输入
第二行 两个已知带有病毒的昆虫编号输出
样例输入
3 5 6 -1 -1 2 7 -1 -1 4 -1 -1 1 9 -1 -1 8 -1 -1
5 1
样例输出
3
思路
最朴素的解法是求出每个点的深度,对于要判断的两个点,先一次次让深度深的走向它的父节点,直到两个点深度一样,再同时让它俩走向所在点的父节点,直到走到同一个节点,这个点就是所求两个点的最近公共祖先朴素LCA代码
#include
然后就有了LCA的倍增优化,倍增优化是利用二进制的性质
dp[i][j]表示第i个节点上移j次所在的节点
具体实现看代码吧倍增优化LCA代码
#include
问题 G: 1234
题目描述
输入
输出
样例输入
thref
样例输出
3
思路
如果长度是3就判断一下和"one"对应有几个位上的字符相等,有大于等于2个数字相等就是1,否则是2#include
问题 H: 寻找虫虫
题目描述
Tips:
在离散数学的定义下:在某个集合上的偏序得出全序的过程称为拓扑排序。
偏序:若集合S上的关系R为自反,反对称和传递的,则称R是集合S上的偏序关系
设R是集合S上的偏序,若对于每个x,y∈xRy或yRx,则称R为集合S的全序。
拓扑排序的流程如下:
\1. 在有向图中选取一个没有前驱节点的点输出
\2. 从图中删除该顶点和所有以该点为尾的弧
一直重复以上步骤,直至顶点全部输出,或图中存在环为止。输入
之后的n行中有整数0和1,对于第i行j列的值,若为1则表示i与j两点有边连接且又向的i点指向j点,若为0则没有边。保证不存在点的自回路(即i == j 时的值为0)输出
若没有回路,则按照题目的描述依次输出图的拓扑排序后的有序数列,每个整数后输出一个空格。
注意尾行的换行。样例输入
4
0 1 0 0
0 0 1 0
0 0 0 0
0 0 1 0
样例输出
3 0 1 2
思路
#include