第一题
1287. 小X与队列 (queue)
题目描述
小X正和同学们做列队的练习。
有n名同学排成一路纵队,编号为i的同学排在从前往后数第i个位置上,即:初始时的队列为1, 2, 3, ..., n。
接下来小X会发出若干条指令,每条指令形如“请编号为x的同学排到最前面来”。(例如:若当前时刻的队列为5, 4, 3, 2, 1,发出一条x=2的指令后,队列变成了2, 5, 4, 3, 1。)
小X发出了很多很多指令,同学们晕头转向不知道该怎么排列。于是就请你算一算,执行完这些指令后,队列应该变成什么样?
输入
第一行两个用空格隔开的正整数n和m,分别表示人数和指令数。
第二行m个用空格隔开的正整数x[i],按顺序表示每次指令的x值。
输出
输出仅有一行包含n个正整数,相邻两个数之间用一个空格隔开,表示执行完所有指令后的队列。
样例输入
4 3
2 3 2
样例输出
2 3 1 4
数据范围限制
对于30%的数据,1<=n,m<=1000
对于另外30%的数据,n=m,且1~n每个数在x[i]中恰好出现一次。
对于100%的数据,1<=n,m<=100000
提示
样例解释
第一条指令前:1 2 3 4
第一条指令后(x=2):2 1 3 4
第二条指令后(x=3):3 2 1 4
第三条指令后(x=2):2 3 1 4
思路
这题其实非常简单,输入后,从m~1循环。用一个b数组来存第a[i]这个编号的小伙伴是否已经拉到了最前面。然后就在循环里判断如果b[a[i]]没有拉到前面,如果没有我们就用c数组存下a[i]的值,把b[a[i]]的值改为已经拉到了最前面。
核心代码
for(int i=m;i>=1;i--)
{
if(b[a[i]]==0)
{
c[k++]=a[i];
b[a[i]]=1;
}
}
for(int i=0;i<k;i++)
printf("%d ",c[i]);
for(int i=1;i<=n;i++)
if(b[i]==0)printf("%d ",i);
代码信息
时间复杂度 | 总时间 |
---|---|
Θ(n) | 3m+n |
第二题
1397. 小幸福(e)
题目描述
有n个小朋友,他们商量在保证作业做完的前提下出去玩。第i个小朋友的可以玩耍时间为Si~Ti。这里Si~Ti表示的是时间段,比如Si=2,Ti=4,那么意味着这位小朋友在时刻1不能玩,时刻2、3、4可以去玩,时刻4以后都不能出去玩。如果在某个时刻,在一起玩的小朋友个数不少K个,那么这一时刻就是幸福的。现在你要求出所有幸福的时刻长度。
输入
三行 第一行:n k (n个小朋友,一起玩的小朋友达到k个为幸福)
第二行:S1 S2 ... Sn
第三行:T1 T2 ... Tn
输出
一行:幸福时刻的长度
样例输入
4 3
1 2 2 4
5 2 4 6
样例输出
2
数据范围限制
50% n<=1000 1<=Si<=Ti<=1000
100% n<=100000 1<=Si<=Ti<=1000000000
提示
时刻 1 2 3 4 5 6
第一个小朋友玩耍时间:X X X X X
第二个小朋友玩耍时间: X
第三个小朋友玩耍时间: X X X
第四个小朋友玩耍时间: X X X
第2分钟和第4分钟一起玩耍的小朋友达到了3个所以是幸福的时刻,幸福时刻长度为2。
思路
这一题要定义一个二维数组a[i][0]用来存时刻,a[i][1]用来存是是开始还是结束,进去赋值为1,出来赋值为-1。注意:结束时刻要加一。然后把整个数组一起排序,循环i~n*2,一次用来循环同一个时间点的刻度,算完这个时刻剩多少人后判断是否大于k。把ans加上a[j][0]-a[i][0]就行了。最后i=j。
核心代码
int i=1,s=0,ans=0,now=0;bool w=false;
while(i<=n*2)
{
int j=i;
while(a[j][0]==a[i][0])
{
s=s+a[j][1];
j++;
}
if(s>=k)
ans=ans+a[j][0]-a[i][0];
i=j;
}
代码信息
时间复杂度 | 总时间 |
---|---|
Θ(n*log(n)) | 3n+n*log(n) |
第三题
1392. 下落的小球(five)
题目描述
有一棵满二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右编号为1,2,3,...,2^D-1。在结点1处放一个小球,它会往下落。每个内结点上都有一个开关,初始全部关闭,当每次有小球落到一个开关上时,它的状态都会改变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否者往右走,直到走到叶子结点。
一些小球从结点1处依次开始下落,最后一个小球将会落到哪里呢?
输入
输入文件five.in
只有一行共有二个正整数:d k (其中d为叶子深度,k为小球个数,1 <= k <= 2^(d-1) )
输出
输出文件five.out
只有一行且只有一个正整数:第k个小球最后所在的叶子编号
样例输入
16 12345
样例输出
36358
数据范围限制
50% 的数据: 1 <= d <= 40
80% 的数据: 1 <= d <= 60
100% 的数据: 1 <= d <= 100
思路
这道题其实也不算难,只是高精度乘除分。 首先,我们了解一下上面那个链接,然后再推一下满二叉树的特性:
(1)二叉树是n个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。下图展示了一棵普通二叉树,根节点是A,其中G、I、J、F成为叶子节点。
(2)满二叉树:在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子结点都在同一层上,这样的二叉树称为满二叉树。
满二叉树的特点有:
1)叶子只能出现在最下一层。出现在其它层就不可能达成平衡。
2)非叶子结点的度一定是2,即他们的下一层都有两个结点。
3)在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。
(3)二叉树的顺序存储结构就是使用一维数组存储二叉树中的结点,并且结点的存储位置,就是数组的下标索引。
对于每一个球,我们都能推出他应该向左还是向右,所以利用4),我们就能得到其最后球最后在哪个结点。
核心代码
while(f>='0'&&f<='9')
{
k[0]+=1;
k[k[0]]=f-'0';
f=getchar();
}
a[0]=1;
a[1]=1;
for(int i=1;i<d;i++)
{
for(int j=1;j<=a[0];j++)
a[j]*=2;
for(int j=1;j<=a[0]+1;j++)
{
a[j+1]+=a[j]/10;
a[j]=a[j]%10;
}
if(k[k[0]]%2==0)
{
a[1]++;
for(int j=1;j<=a[0];j++)
{
a[j+1]+=a[j]/10;
a[j]=a[j]%10;
}
}
if(a[a[0]+1]!=0)
a[0]++;
int bj=0;
if(k[k[0]]%2==1)k[k[0]]+=1;
for(int j=js;j<=k[0];j++)
{
k[j+1]+=k[j]%2*10;
if(k[j]/2!=0||bj==1)
{
k[j]=k[j]/2;
bj=1;
}
else if(bj==0)js++;;
}
}