目录
一、小q的数列
题目链接:小q的数列
题目描述
小q最近迷上了各种好玩的数列,这天,他发现了一个有趣的数列,其递推公式如下:
f[0]=0 f[1]=1;
f[i]=f[i/2]+f[i%2];(i>=2)
现在,他想考考你,问:给你一个n,代表数列的第n项,你能不能马上说出f[n]的值是多少,以及f[n]所代表的值第一次出现在数列的哪一项中?(这里的意思是:可以发现这个数列里某几项的值是可能相等的,则存在这样一个关系f[n'] = f[n] = f[x/2]+f[x%2] = f[x]...(n'<n<x) 他们的值都相等,这里需要你输出最小的那个n'的值)(n<10^18)
输入描述:
输入第一行一个t 随后t行,每行一个数n,代表你需要求数列的第n项,和相应的n' (t<4*10^5)
输出描述:
输出每行两个正整数 f[n]和n',以空格分隔
示例1
输入
复制2 0 1
2 0 1
输出
复制0 0 1 1
0 0 1 1
个人题解:f[n]=f[n/2]+f[n%2],举一个例子,比如说f[66].
f[66]=f[33]+f[0]
=f[16]+f[1]=f[16]+1
=f[8]+f[0]+1
=f[4]+f[0]+1
=f[2]+f[0]+1
=f[1]+1=1+1
这里的f[n]仔细看看其实也就是n的二进制形式中1的个数,为什么这么说呢,每一次除以二,其实就是右移一位,然后n%2,也就是看看最右边数是1还是0,那么这不就是求1的个数吗
至于求最早出现的相同值的n,只要你求出了之前1的个数,那么这个数其实就是连着1的个数,也就是2的1的个数的次方-1.换成二进制表达就是1左移1的个数位-1(1是long long类型)
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n; int t; ll f(ll x) { //二进制下有几个1 ll sum=0; while(x){ if(x&1==1){ sum++; } x=x>>1; } return sum; } ll zuixiao(ll x) { return ((1LL<<x)-1); } int main() { scanf("%d",&t); while(t--){ scanf("%ld",&n); ll x=f(n); printf("%ld %ld\n",x,zuixiao(x)); } return 0; }
二、求先序排列
题目链接:求先序排列
题目描述
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度 ≤ 8)。
输入描述:
2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。
输出描述:
1行,表示一棵二叉树的先序。
示例1
输入
复制BADC BDCA
BADC BDCA
输出
复制ABCD
ABCD
个人题解:知道中序排列和后序排列以及中序排列和先序排列,都是可以求出这棵二叉树的也就可以求出对应的排列。但是知道先序排列和后序排列的情况下是无法求出中序排列的。
为什么呢?因为中序排列是左根右,而先序排列从前往后可以知道根,后序排列重后往前可以知道根,对应的中序排列以根为界限即可知道左子树和右子树。
来看看本题,知道了中序排列和后序排列,该如何做,代码有解释。
#include<bits/stdc++.h> using namespace std; typedef long long ll; string zhong,hou; void deal(int l1,int r1,int l2,int r2) { //l1,r1其实就是中序排列的从l1到r1的一颗子树 //l2,r2是后序排列 if(l1>r1)return ; char root=hou[r2]; cout<<root; int pos=-1;//记录根的位置 for(int i=l1;i<=r1;i++){ if(root==zhong[i]){ pos=i; break; } } //递归左子树 deal(l1,pos-1,l2,l2+pos-1-l1); //递归右子树 deal(pos+1,r1,r2-r1+pos,r2-1); //这里有个技巧中序排列和后序排列他们的子树长度是一样的 //不会求端点可以列方程求出 } int main() { cin>>zhong>>hou; int l=zhong.size(); deal(0,l-1,0,l-1); }
三、FBI树
题目链接:FBI树
题目描述
我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。
FBI树是一种二叉树[1],它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
1) T的根结点为R,其类型与串S的类型相同;
2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历[2]序列。
[1] 二叉树:二叉树是结点的有限集合,这个集合或为空集,或由一个根结点和两棵不相交的二叉树组成。这两棵不相交的二叉树分别称为这个根结点的左子树和右子树。
[2] 后序遍历:后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。
输入描述:
第一行是一个整数N(0 <= N <= 10)
第二行是一个长度为2N的“01”串。
输出描述:
一个字符串,即FBI树的后序遍历序列。
示例1
输入
复制3 10001011
3 10001011
输出
复制IBFBBBFIBFIIIFF
IBFBBBFIBFIIIFF
备注:
对于40%的数据,N <= 2; 对于全部的数据,N<= 10。
个人题解:本题题意大概如下:
10001011
从中间分,如:
10001011
1000 1011
10 00 10 11
1 0 0 0 1 0 1 1
全是1是I串,全是0则为B串,有0有1是F串
本题可以通过递归来实现,具体如下
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n; char s[1200]; char fbi(int l,int r) { if(l==r)//左点等于右点只有一个点 { //只有一个点 if(s[l]=='0'){ cout<<'B'; return 'B'; } else{ cout<<'I'; return 'I'; } } // int mid=(l+r)/2; char a=fbi(l,mid);//先递归左子树 char b=fbi(mid+1,r);//再递归右子树 //左子树和右子树递归完,开始查看根节点 //而根节点的查看是通过左子树和右子树来比较的 if(b=='B'&&a=='B'){ //全是0 cout<<'B'; return 'B'; } else if(b=='I'&&a=='I') { cout<<'I'; return 'I'; } cout<<'F'; return 'F'; } int main() { scanf("%d",&n); scanf("%s",&s); int l=strlen(s); fbi(0,pow(2,n)-1); return 0; }
四、表达式计算
题目链接:表达式计算
题目描述
给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值
数据可能会出现括号情况,还有可能出现多余括号情况
数据保证不会出现≥231的答案数据保证不会出现\geq 2^{31}的答案数据保证不会出现≥231的答案
数据可能会出现负数情况
输入描述:
仅一行,即为表达式
输出描述:
仅一行,既为表达式算出的结果
示例1
输入
复制(2+2)^(1+1)
(2+2)^(1+1)
输出
复制16
16
备注:
表达式总长度≤30表达式总长度 \leq 30表达式总长度≤30
个人题解:没什么好理解的。可以用栈来写。但这里我用的是递归来写。具体看代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; //表达式求值 string s; int shu(int l,int r) { int num=0; for(int i=l;i<=r;i++){ num=num*10+(s[i]-'0'); } return num; } int cal(int l,int r) { int cnt=0; int pos1=-1,pos2=-1,pos3=-1;//分别记录加减,乘除,和幂次方的最后一次出现的位置 for(int i=l;i<=r;i++){ if(s[i]=='(')cnt++; if(s[i]==')')cnt--; if(cnt<=0){ if(s[i]=='+'||s[i]=='-')pos1=i; if(s[i]=='*'||s[i]=='/')pos2=i; if(s[i]=='^')pos3=i; } } if(pos1==-1&&pos2==-1&&pos3==-1){ if(cnt==0&&s[l]=='('){ return cal(l+1,r-1); } if(cnt>0&&s[l]=='('){ return cal(l+1,r); } if(cnt<0&&s[r]==')'){ return cal(l,r-1); } return shu(l,r); } if(pos1!=-1){ // if(s[pos1]=='+'){ return cal(l,pos1-1)+cal(pos1+1,r); } else{ return cal(l,pos1-1)-cal(pos1+1,r); } } else if(pos2!=-1){ if(s[pos2]=='*'){ return cal(l,pos2-1) * cal(pos2+1,r); } else{ return cal(l,pos2-1) / cal(pos2+1,r); } } else{ if(s[pos3]=='^')return pow(cal(l,pos3-1),cal(pos3+1,r)); } return 0; } int main() { cin>>s; int l=s.size(); cout<<cal(0,l-1); return 0; }