由于深夜点了外卖要1:50才到
闲着没事就补一下题目!
题目如下:
题目描述
In one one-dimensional world there are nn platforms. Platform with index kk (platforms are numbered from 1) is a segment with coordinates [(k-1)m,(k-1)m+l][(k−1)m,(k−1)m+l] , and l<ml<m . Grasshopper Bob starts to jump along the platforms from point 00 , with each jump he moves exactly dd units right. Find out the coordinate of the point, where Bob will fall down. The grasshopper falls down, if he finds himself not on the platform, but if he finds himself on the edge of the platform, he doesn't fall down.
输入格式
The first input line contains 4 integer numbers nn , dd , mm , ll ( 1<=n,d,m,l<=10^{6},l<m1<=n,d,m,l<=106,l<m ) — respectively: amount of platforms, length of the grasshopper Bob's jump, and numbers mm and ll needed to find coordinates of the kk -th platform: [(k-1)m,(k-1)m+l][(k−1)m,(k−1)m+l] .
输出格式
Output the coordinates of the point, where the grosshopper will fall down. Don't forget that if Bob finds himself on the platform edge, he doesn't fall down.
题意翻译
题目描述:在一坐标轴上给出n块板子,每个板子所占的空间为[(k-1)m,(k-1)m+l](l<m),一个青蛙从原点0起跳,每次跳d距离远,问最后青蛙会落在哪里(没落在板子上就结束跳跃) 输入:一行四个整数n,d,m,l 输出:一个整数,即青蛙最后的落点 1<=n,d,m,l<=10^6 l<m
Translated by 稀神探女
输入输出样例
输入 #1复制
2 2 5 3输出 #1复制
4输入 #2复制
5 4 11 8输出 #2复制
20
测试的时候由于没看懂这个k是个啥玩意,就没看懂题目,害。
其实题目好像很简单的样子,想清楚这个k就行,应该算是一个数学题,思路草稿:
也就是说,其中n为板子数,d为青蛙弹跳力,m为第一块板子距离原点的距离,l为板子宽度,易得板子与板子间的距离为m-l。
且题目要我们输出的是青蛙掉落的点。
#include<stdio.h>
int main()
{
long long n,d,m,l,ans=0;
scanf("%lld %lld %lld %lld",&n,&d,&m,&l);
for(int k=1; k<=n; k++)//k代表第k块板子
{
if(ans<((k-1)*m))//如果本次青蛙跳跃后达不到板子左边缘则落入水中结束跳跃
break;
while(ans<=(k-1)*m+l)//跳的上板子就一直跳,直到跳出了板子右边缘
{
ans=(((k-1)*m+l)/d)*d+d;//*d/d是为了取整
}
}
printf("%lld",ans);
return 0;
}
--------------------------------------------------- -------------------------- --------------------------------------------------
上午先补题 这道题题目如下
题意描述
关于 Codeforces 的网站 king Copa 经常被报道,使得它在要使用网站进行训练和比赛的人之间迅速流行开来。最近, Copa 明白,要征服世界,他需要组织世界 Codeforces 锦标赛。他希望在这次比赛之后之后,最聪明的人将成为被挑选出来成为他的下属,然后征服世界最艰难的部分将会完成。
Codeforces 世界总决赛的最后一轮定于 YYYY 年 MMMM 月 DDDD 日举行,其中 DDDD 是当天的日期, MMMM 是当月的月份, YYYY 是当年的年份的最后两位。Bob 很幸运地能成为来自 Berland 的一名决赛选手。但有一个问题:根据比赛规则,所有参赛者在决赛时必须年满 1818 岁。 Bob 出生于 BYBY 年, BMBM 月,BDBD 日。这个日期记录在他的护照上,他的护照复印件已经寄给了组织者。但是 Bob 了解到,在不同的国家,日期的书写方式是不同的。例如,在美国,先写月份,然后写日期,最后写年份。
鲍勃想知道是否有可能重新排列他出生日期的数字,以便他在 YYYY 年, MMMM 月, DDDD 日那天至少 1818 岁。他看出,在他的祖国,日期写的顺序不一样。请帮帮他。 根据另一个奇怪的规则,合格的参赛者必须与决赛日期出生在同一个世纪。如果决赛当天刚好是参赛者的 1818 岁生日,则他可以参加。
因为我们只考虑从 20012001 年到 20992099 年的决赛年份,所以使用以下规则:如果年份的数字可以被 44 整除,那么年份就是闰年。
输入格式:
第一行包括三个数字 DD,MM,YYDD,MM,YY ,第二行包括三个数字 BD,BM,BYBD,BM,BY ,数据保证两个日期的正确性,并且 BYBY 和 YYYY 保证在 [ 01 ,99 ][01,99] 中。
输出格式:
如果可能通过重新排列出生日期的顺序,让 Bob 在比赛当天至少 1818 岁,则输出 YES 。如果不能,则输出 NO。
输入输出样例
输入 #1复制
01.01.98 01.01.80输出 #1复制
YES输入 #2复制
20.10.20 10.02.30输出 #2复制
NO输入 #3复制
28.02.74 28.02.64输出 #3复制
NO
思路如下图(感觉是用枚举吧)(还挺麻烦的样子)
喔 对了,最近不是自己学了c++不,所以决定用c++来写写看
一开始写着c++的代码一直交c,导致编译错误
后来发现了又因为判断条件写的太复杂了,可能某个小地方有点错误导致有一个测试点过不了
#include<bits/stdc++.h>
using namespace std;
int dday[14]={0,31,29,31,20,31,30,31,31,30,31,30,31};
int dd,mm,yy;//比赛日期
bool check(int year,int month,int day)//判断是否是个合法日期
{
int sign = 0;//默认为非闰年
if(year % 4 == 0)
sign = 1;//如果是闰年标记一下
if(month > 12)
return false;
if(day > dday[month])
return false;
else if(sign == 0 && month == 2 && day>28)
return false;
else if(sign == 0 && month == 2 && day>29)
return false;
else
return true;
}
bool adult(int year,int month,int day)//判断是否成年
{
if(yy - year > 18)
return true;
else if(yy - year <=17)
return false;
else if(yy - year == 18)
{
if(mm - month > 0)
return true;
else if(mm - month < 0)
return false;
else if(mm - month == 0)
{
if(dd-day >= 0)
return true;
else
return false;
}
}
return false;
}
int main()
{
int bd,bm,by;//bob生日
scanf("%d.%d.%d %d.%d.%d",&dd,&mm,&yy,&bd,&bm,&by);
if(check(by,bm,bd)&&adult(by,bm,bd)){
cout<<"YES";
return 0;
}
if(check(by,bd,bm)&&adult(by,bd,bm)){
cout<<"YES";
return 0;
}
if(check(bm,by,bd)&&adult(bm,by,bd)){
cout<<"YES";
return 0;
}
if(check(bm,bd,by)&&adult(bm,bd,by)){
cout<<"YES";
return 0;
}
if(check(bd,by,bm)&&adult(bd,by,bm)){
cout<<"YES";
return 0;
}
if(check(bd,bm,by)&&adult(bd,bm,by)){
cout<<"YES";
return 0;
}
cout<<"NO";
return 0;
}
后面想想,我可以只把判断满足条件的情况,如何其他情况全部返回false即可,修改之后的代码如下,简洁了不少。
莫名其妙,这题明明很简单,我弄了好久,一直有一个测试点过不了,估计就是一点点小错误导致的,然后重新打了一遍就过了,害。(注意点和我的错误点都在代码中加了注释)
#include<bits/stdc++.h>
using namespace std;
int dday[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31}; //月份所对应的天数用一个数组储存,方便取用
int dd,mm,yy,bd,bm,by;
bool check(int year,int month,int day)//判断是否是个合法日期
{
if(month > 12 || month < 1 || day < 1 || day > 31 || year < 1 || year > 99)//题目只保证了 输 入 数 据 中的年不越界
return false;
else if(day > dday[month])//包含闰年二月份的判断了
return false;
else if(year % 4 !=0 && month == 2 && day>28)
return false;
///如果成功运营到此处说明是个合法日期,在此基础上接着判断是否成年
//判断是否成年
if(yy - year > 18)
return true;
else if(yy - year == 18 && mm - month > 0)
return true;
else if(yy - year == 18 &&mm - month == 0&&dd-day >= 0)
return true;///else if()是指不满足yy-year>18之外满足()的情况,所以一定要加上yy-year==18这个前提条件
else//除上述三种情况之外都不成年
return false;
}
int main()
{
scanf("%d.%d.%d %d.%d.%d",&dd,&mm,&yy,&bd,&bm,&by);
//枚举六种搭配进行check判断
if(check(by,bm,bd)== true)cout<<"YES";
else if(check(by,bd,bm) == true)cout<<"YES";
else if(check(bm,by,bd) == true)cout<<"YES";
else if(check(bm,bd,by) == true)cout<<"YES";
else if(check(bd,by,bm) == true)cout<<"YES";
else if(check(bd,bm,by) == true)cout<<"YES";
else cout<<"NO";
return 0;
}
下午,开始刷题(第二周题组)
题目如下:
题目描述
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度\le 8≤8)。
输入格式
22行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。
输出格式
11行,表示一棵二叉树的先序。
输入输出样例
输入 #1复制
BADC BDCA输出 #1复制
ABCD
思路:
1.输入的是一个二叉树的中序序列和后序序列
2.由后序序列的特点可知,后序序列末尾结点为根结点。
3.在中序序列中找到该结点,它的两边是根结点的两棵子树,而他们所对应的后序序列在总后序序列中可以找到,最后一个结点为子树的根。
4.题目要求的是先序序列,所以我们要不断寻找根,根的子树的根,输出根,即得到先序学列,寻找方法都是一样的所以我们想到用递归。
由于在写代码的过程遇到了困难,感觉不断地提子字符串很麻烦,所以又学到了一手函数,再次感叹c++就是比c牛掰qwq!!
SUBSTR ()函数(子串截取函数)
substr函数格式 (俗称:字符截取函数)
格式1: substr(string string, int a, int b);
格式2:substr(string string, int a) ;
解析:
格式1:
1、string 需要截取的字符串
2、a 截取字符串的开始位置(注:当a等于0或1时,都是从第一位开始截取)
3、b 要截取的字符串的长度
格式2:
1、string 需要截取的字符串
2、a 可以理解为从第a个字符开始截取后面所有的字符串。
挣扎了很久之后发现学了这个函数我也搞不出来这道题,感觉自己的代码好像没什么毛病了可是就是一直报错.......大佬的代码是这样子的,完全正确,高级又简单:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void beford(string in,string after)
{
if (sizeof(in)>0)
{
char ch=after[after.size()-1];
cout<<ch;//找根输出
int k=in.find(ch);
beford(in.substr(0,k),after.substr(0,k));
beford(in.substr(k+1),after.substr(k,in.size()-k-1));//递归左右子树;
}
}
int main()
{
string inord,aftord;
cin>>inord;
cin>>aftord;//读入
beford(inord,aftord);
cout<<endl;
return 0;
}
然而我的..
#include<bits/stdc++.h>
using namespace std;
string intree,postree;
int finds(string ch,char poos,int l)
{
for(int i=0;i<l;i++)
if(ch[i] == poos)
return i;
}
void pretree(string in,string pos,int l)
{
if(l>0)
{
char root=pos[l-1];
cout<<root;//输出根
int k=finds(in,root,l);
pretree(substr(in,0,k),substr(pos,0,k));
pretree(substr(in,k+1,l-1),substr(k,l-k-1));
}
}
int main()
{
cin>>intree>>cin>>postree;
int len=strlen(postree);
pretree(intree,postree,len,len);
return 0;
}
都运行不了.....!!我明明是按照格式使用的可是会出现这样子的报错..!!
放弃这个方法了,还是走dfs吧..........................................
如何由后序序列和中序序列推出前序序列,很明白!但就是捋不清代码怎么写。借鉴了别人的之后有了思路:
通过记录中序序列起止点下标和对应后序序列起止点下标来模拟提出子字符串!(这还真是个非常不错的好办法),通过手算模拟过程推出各个下标的规律,发现还需要知道右子树的结点个数会更好进行递归操作,那就在“遍历中序序列(注意这里是从后往前遍历//是为了求右子树结点个数)寻找根结点的过程记录一下右子树结点个数”,便于描述左子树和右子树的中序序列和后序序列的起末点下标。
自定义这样子的一个函数
void dfs(int start1,int end1,int start2,int end2)
找到当前根结点在中序序列中的位置下标i,并记录了右子树序列个数k之后,
下一步通过递归操作分别处理左右子树
通过找规律得到
左子树中序序列起点:start1
左子树中序序列终点:i-1
左子树后序序列起点:start2
左子树后序序列终点:end2-k-1
右子树中序序列起点:i+1
右子树中序序列终点:end1
右子树后序序列起点:end2-k
右子树后序序列终点:end2-1
结束dfs的条件是当起点大于终点时,即:
if(start1>end1||start2>end2)//如果起点下标大于终点,回溯
return;
#include<bits/stdc++.h>
using namespace std;
char s1[10],s2[10];
void dfs(int start1,int end1,int start2,int end2)//start1:中序序列起点下标,end1:中序序列终点下标,start2:后序序列起点下标,end2:后序序列终点下标
{
if(start1>end1||start2>end2)//如果起点下标大于终点,回溯
return;
char ch=s2[end2];//输出后序序列末尾元素
cout<<ch;
for(int i=end1,k=0;i>=start1;k++,i--)///从末尾往前遍历,所以其中k记录当前根的右子树元素个数
{
if(s1[i]==ch)
{
dfs(start1,i-1,start2,end2-k-1);//递归处理左子树
dfs(i+1,end1,end2-k,end2-1);//递归出库右子树
///右子树后序序列下标范围是end2-k到end2-1
}
}
}
int main()
{
cin>>s1>>s2;
int len=strlen(s1);
dfs(0,len-1,0,len-1);//中序与后序序列的起末点下标
return 0;
}
感谢乐于助人的同行小伙伴,我终于弄懂了这题,这道题的理解对我后续的题目帮助肯定会很大的。
接着做了并查集的题目,感谢某非常非常非常好的学长讲的超级棒,让我理解的很透彻啦。
题目如下
题目背景
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
题目描述
规定:xx 和 yy 是亲戚,yy 和 zz 是亲戚,那么 xx 和 zz 也是亲戚。如果 xx,yy 是亲戚,那么 xx 的亲戚都是 yy 的亲戚,yy 的亲戚也都是 xx 的亲戚。
输入格式
第一行:三个整数 n,m,pn,m,p,(n,m,p \le 5000n,m,p≤5000),分别表示有 nn 个人,mm 个亲戚关系,询问 pp 对亲戚关系。
以下 mm 行:每行两个数 M_iMi,M_jMj,1 \le M_i,~M_j\le N1≤Mi, Mj≤N,表示 M_iMi 和 M_jMj 具有亲戚关系。
接下来 pp 行:每行两个数 P_i,P_jPi,Pj,询问 P_iPi 和 P_jPj 是否具有亲戚关系。
输出格式
pp 行,每行一个
Yes
或No
。表示第 ii 个询问的答案为“具有”或“不具有”亲戚关系。输入输出样例
输入 #1复制
6 5 3 1 2 1 5 3 4 5 2 1 3 1 4 2 3 5 6输出 #1复制
Yes Yes No
代码如下
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
int f[10000];
int findd(int x)//找祖宗
{
if(f[x]==x)//自己就是自己的爸爸
return x;
else
return f[x]=findd(f[x]);//顺便把内部结点的爸爸直接改成老大
}
void combine(int x,int y)
{
if(findd(x)!=findd(y))
f[findd(x)]=findd(y);
}
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)//初始化f数组
f[i]=i;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
combine(a,b);
}
for(int i=0;i<q;i++)
{
int a,b;
cin>>a>>b;
if(findd(a) == findd(b))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
当时看并查集的时候就浏览了一遍,下午讲课讲了,晚上学长又讲的很清楚,所以写一波自己的认识和思路吧。
┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄*
并查集,通俗的讲就是把一伙的归到一起去。/把一家的人放到同一棵树上去。
就这道题而言,就是由一些基本操作组成的:初始化父亲数组,查祖宗,合并小集合,判断。
初始化:起初用f[x]=x,使得每个人是自己的爸爸///有点奇怪 应该说就是自己就是自己的老大!
查祖宗:如果f【x】=x,那就是找到祖宗了,否则,通过递归一直往上找直到找到f【x】=x的点,两个人的祖宗一样那他们肯定就是一家的嘛!这里可以有一个压缩路径的操作,即f[x]=findd(f[x]),这样子即把所有内部结点都直接指向根结点了,这样子查找祖宗的时候就可以一步到位!节省时间,呸,可以减小时间复杂度!
合并集合(不能漏了噢):由于给出的信息,一个人可能同时和几个人有关系嘛,不能丢三落四,如果输入一对有亲戚关系的人a和b,仅仅令f[a]=b的话,那么如果有另一个信息是a和c有亲戚关系的话,变成了f[a]=c,a和b的关系就断开了。所以我们要用这么一个合并操作避免这样的事情发生,即,给出两个有亲戚关系的人a,b,如果他们的祖先不一样,就让他们两其中一个人的祖先认另一个人为祖先,这样子就把他们联系起来了,有了合并操作,就可以不需要f[a]=b这个操作了,因为当a和b自己是自己的祖先时候,"他们两其中一个人的祖先认另一个人为祖先"就等同于f[a]=b,想明白这个就可以理解为什么可以输入数据时,直接进行合并操作了。ok并查集确实简单。
┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┅┄┄*
今天就先到这里,毕竟凌晨就是第二天了qwq
有一说一,c++一用起来,就停不下来了,不想回去了