根据大纲梳理一遍,也在全文最后补充了最几年的决赛真题,全文基于C++编写,希望对你有所帮助
关于省赛的反思:
1.我的Code::Block 20.03在机房的电脑调不出来(我决定还是用DEV)
2.暴力算法枚举不要指望学校机房的CPU
3.注意数据的规模,写完一部分代码块记得调试运行一下
ps:真题做下来不难发现小明是个究极强迫症QVQ,期末没有什么时间写,还要英语四级,提前cue借口,但还是加油!!
——以上是2021年的整理
经过寒假对考研数据结构的复习,对算法有了新的感悟) 。
继续整理的栈 队列 树 图 排序
C/C++程序设计基础:包含使用 C/C++编写程序的能力。该部分不考查选手对某一语法的理解程度,选手可以使用自己喜欢的语句编写程序。选手可在 C 语言程序中使用标准 C 的库函数,在 C++语言程序中使用标准 C++的库函数(包括 C 库、STL 等)。
计算机算法:枚举、排序、搜索、计数、贪心、动态规划、图论、数论、博弈论*、概率论*、计算几何*、字符串算法等。
数据结构:数组、对象/结构、字符串、队列、栈、树、图、堆、平衡树/线段树、复杂数据结构*、嵌套数据结构*等。
vector容器可以动态地扩展(原数据拷贝新空间)
#include
#include
using namespace std;
int main(){
vector<int> v1;//默认构造
v1.push_back(1);//尾部插入
v1.pop_back();//尾部删除最后一个元素
v1.insert(v1.begin(),100);//在迭代器指定位置插入数据
v1.erase(v1.begin());//删除迭代器指定位置
v1.clear();//清空
cout<<v1.capacity()<<endl;//输出容量
cout<<v1.size()<<endl;//元素个数
v1.resize(15,100);//指定默认填充值拓展容量
cout<<v1[0]<<" "<<v1[1]<<endl; //输出数据
vector<int> v2(v1.begin(),v1.end());//区间方式构造
vector<int> v3(10,100);//v3中有10个100
vector<int> v4(v3);//拷贝构造
if(v1.empty()){//判断是否为空
cout<<"空"<<endl;
}
v1.reserve(100);//预留空间,元素不可以访问
v1.swap(v2);//交换两个容器中的数据
vector<int>(v).swap(v)//巧用可以压缩空间
return 0;
}
一般会结合bfs使用
#include
#include
using namespace std;
int main(){
queue<int> q;
q.push(1);//入队
q.push(2);
cout<<"队列是否为空:"<<q.empty()<<endl;
cout<<"队头元素是:"<<q.front()<<endl;
cout<<"队尾元素是:"<<q.back()<<endl;
q.pop();//出队
cout<<"队列元素个数:"<<q.size()<<endl;
return 0;
}
可以很方便地用Key值查找value值
map容器:不允许有重复key值
multimap容器:允许有重复key值
#include
#include
using namespace std;
class cmp{//指定降序插入
public:
bool operator()(int v1,int v2){
return v1>v2;
}
};
int main(){
map<int,int> m1;//创建map容器
map<int,int> m2(m1);//拷贝构造
map<int,int,cmp> m3;//按照指定规则排序 (默认按照key的升序插入)
m1.insert(pair<int,int>(2,30));//插入数据
m1.insert(make_pair(1,10));//插入数据(这种方式不用写数据类型)
m1.insert(make_pair(1,20));//不允许插入重复的key值(保留先插入的)
cout<<"容器是否为空:"<<m1.empty()<<endl;
cout<<"容器元素个数:"<<m1.size()<<endl;
cout<<"容器中有几个key为1的值:" <<m1.count(1)<<endl;
map<int,int>::iterator pos = m1.find(2);//查找有没有key为2的元素,返回迭代器
if(pos!=m1.end()){
cout<<"找到了"<<endl;
}
m1.swap(m2);//交换两个容器的元素
cout<<m2[1]<<endl;//利用key访问value值
m2.erase(m2.begin());//删除迭代器指定元素
m2.erase(2);//根据指定的key值删除
m2.erase(m2.begin(),m2.end());//根据指定区间删除
m2.clear();//清空容器
return 0;
}
问题描述
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。 在冒泡排序中,每次只能交换相邻的两个元素。 小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。 例如,对于字符串 lan 排序,只需要 1次交换。对于字符串 qiao 排序,总共需要4次交换。 小蓝的幸运数字是V,他想找到一个只包含小写英文字母的字符串,对这个串中的字符进行冒泡排序,正好需要V次交换。请帮助小蓝找一个这样的字符串。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中可以包含相同的字符。
输入格式
输入一行包含一个整数 ,为小蓝的幸运数字。
输出格式
输出一个字符串,为所求的答案。
样例输入
4
样例输出
bbaa
一个很赞的BFS和DFS讲解
引子:
问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.把第二个图的局面记为:123.46758 显然是按从上到下,从左到右的顺序记录数字,空格记为句点。本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出 3
样例输入
13524678.
46758123.
样例输出 22
代码梳理
1.将九宫格的初始状态和目标状态以二维数组的形式存储,并标记初始空白格的位置
2.从初始状态的空白格开始广度优先遍历
->终止条件,达到目标状态,输出步骤/不存在方案 输出-1
->搜索:将当前状态入队,从队头开始,把空白格向四个方向挪动,如果可以挪动,判断是否满足目标九宫格,不满足再把当前状态入队。
当无法再挪动时,在从队头寻找新的状态,直到队空。
3.剪枝:其中在bfs时,如果遇到之前已经出现的状态就不需要再遍历了。
实现代码
#include
#include
#include
#include
using namespace std;
char start[4][4];
char goal[4][4];
int df[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
map<string,int> vis;
struct Node{//结点结构体,存储当前坐标,步骤,九宫格状态
int x,y;
long long step;
char Map[4][4];
};
bool check_g(Node a){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
if(a.Map[i][j]!=goal[i][j])
return false;//如果有一个位置不符合就返回false
}
}
return true;//全部符合就返回true
}
bool check_cf(Node a){//判断剪枝
string s="";
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
s+=a.Map[i][j];
}
}
if(vis[s]>0)
return false;
vis[s]++;
return true;
}
int bfs(int x1,int y1){//传入空白格的标记坐标
Node cur,next;//创立两个结点 (当前和下一个)
cur.x=x1;// 传入当前空白格的坐标
cur.y=y1;
cur.step=0;//初始化步骤数
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cur.Map[i][j]=start[i][j];//对当前九宫格初始化
}
}
queue<Node> Q;//创建一个队列
Q.push(cur);//将当前结点传入队列
if(check_g(cur)){//检查是否已经转化成目标九宫格
return cur.step;//已经是目标九宫格返回所需要的步骤
}
while(!Q.empty()){//如果队列不为空
cur=Q.front();//取出队头元素
Q.pop();//出队
for(int i=0;i<4;i++){
next.x=cur.x+df[i][0];//分别将空白格向四个方向移动
next.y=cur.y+df[i][1];
for(int i1=1;i1<=3;i1++){
for(int j=1;j<=3;j++){
next.Map[i1][j]=cur.Map[i1][j];//存入下一个九宫格的状态
}
}
next.step=cur.step+1;//挪动的步骤+1
if(next.x>=1&&next.x<=3&&next.y>=1&&next.y<=3){//如果在边界内
swap(next.Map[next.x][next.y],next.Map[cur.x][cur.y]);//移动空白格
if(check_cf(next)){//检查是否重复
if(check_g(next)){//检查是否满足需求
return next.step;
}
Q.push(next);//把当前结点入队
}
}
}
}
return -1;
}
int main(){
int x1,y1;//空白格的位置
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cin>>start[i][j];//输入起始九宫格状态
if(start[i][j]=='.'){
x1=i; //遇到 。标记位置
y1=j;
}
}
}
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cin>>goal[i][j];//输入目标九宫格的状态
}
}
cout<<bfs(x1,y1)<<endl;//bfs寻找最小步骤
return 0;
}
引子:棋盘中的棋子摆放方法有几种
问题描述
很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入格式
输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数城市从1开始依次编号,1号城市为首都。接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。
输出格式
输出一个整数,表示大臣J最多花费的路费是多少。
#include
#include
#include
using namespace std;
struct road{
int d,l;
};
vector<road> G[10000];
int visit[10000];
int totallen,maxlen,start;
void dfs(int s){
if(maxlen<totallen){
maxlen=totallen;
start=s;
}
for(int i=0;i<G[s].size();i++){
road k=G[s][i];
if(!visit[k.d]&&k.l){
visit[k.d]=1;
totallen+=k.l;
dfs(k.d);
visit[k.d]=0;
totallen-=k.l;
}
}
return;
}
int main(){
int n,a,s;
cin>>n;
road r;
for(int i=0;i<n-1;i++){
cin>>s>>r.d>>r.l;
G[s].push_back(r);
a=r.d;
r.d=s;
G[a].push_back(r);
}
memset(visit,0,sizeof(visit));
totallen=0;
visit[1]=1;
dfs(1);
memset(visit,0,sizeof(visit));
totallen=0;
maxlen=-1;
visit[start]=1;
dfs(start);
cout<<((11+10+maxlen)*maxlen)/2<<endl;
return 0;
}
一个很好的回溯算法总结
题型:组合,切割,子集,排列,棋盘
回溯模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
#include
#include
using namespace std;
vector<int> path;
vector< vector<int> > result;//这里要注意<>中的空格不然会当>>报错
void backtracking(int n,int k,int starIndex){
if(path.size()==k){
result.push_back(path);
for(int i=0;i<path.size();i++){
cout<<path[i];
}
cout<<endl;
return;
}
for(int i=starIndex;i<=n-(k-path.size())+1;i++){//优化剪枝
path.push_back(i);
backtracking(n,k,i+1);
path.pop_back();
}
}
int main(){
int n,k;//返回 1 ... n 中所有可能的 k 个数的组合
cin>>n>>k;
backtracking(n,k,1);
return 0;
}
#include
#include
using namespace std;
vector<int> path;
vector< vector<int> > result;
int targetsum;
void backtracking(int n,int k,int sum,int starIndex){
if(sum>targetsum){
return;
}
if(path.size()==k){
if(sum==targetsum){
result.push_back(path);
for(int i=0;i<path.size();i++){
cout<<path[i];
}
cout<<endl;
}
return;
}
for(int i=starIndex;i<=n;i++){
sum+=i;
path.push_back(i);
backtracking(n,k,sum,i+1);
sum-=i;
path.pop_back();
}
}
int main(){
int n,k;//返回 1 ... n 中所有可能的 k 个数的组合使其达到目标值
cin>>n>>k>>targetsum;
backtracking(n,k,0,1);
cout<<"总共有:"<<result.size()<<"取法"<<endl;
return 0;
}
#include
#include
using namespace std;
vector<string> path;
vector< vector<string> > result;
bool isPalindrome(string s,int start,int end){
for(int i=start,j=end;i<j;i++,j--){
if(s[i]!=s[j]){
return false;
}
}
return true;
}
void backtracking(string s,int startIndex){
if(startIndex>=s.size()){
result.push_back(path);
return;
}
for(int i=startIndex;i<=s.size();i++){
if(isPalindrome(s,startIndex,i)){
string str=s.substr(startIndex,i-startIndex+1);//获取分割子串
path.push_back(str);
}
else{
continue;
}
backtracking(s,i+1);
path.pop_back();
}
}
int main(){
string s;
cin>>s;
backtracking(s,0);
cout<<"总共有:"<<result.size()<<"取法"<<endl;
return 0;
}
#include
#include
using namespace std;
vector<int> path;
vector< vector<int> > result;
vector<int> nums;
void backtracking(vector<int> nums,int startIndex){
result.push_back(path);
for(int i=0;i<path.size();i++){
cout<<path[i];
}
cout<<endl;
if(startIndex>=nums.size()){
return;
}
for(int i=startIndex;i<nums.size();i++){
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
}
int main(){
int n,num;
cin>>n;//输入要求子集的集合
for(int i=1;i<=n;i++){
cin>>num;
nums.push_back(num);
}
backtracking(nums,0);
cout<<"总共有:"<<result.size()<<"子集"<<endl;
return 0;
}
引子:Fibonacci sequence
利用递推公式:Fib(n+2) = Fib(n+1) + Fib(n),Fib(1) = Fib(2) = 1
利用递归的时间复杂度O(2^n),想象成一棵二叉树,每次计算一个新的Fib(n)就要展开一次分支,效率很低。
但是如果把得出结果的Fib(n)、Fib(n-1)保存,Fib(n+1)用到的时候直接调用,是不是就把效率提高了。这就是动态规划的思想。下面利用动态规划解决一下Fibonacci sequence问题。
#include
#define MAX 10000
using namespace std;
int Fib(int n){
int F[MAX];//用数组存储结果
F[1]=F[2]=1;
for(int i=3;i<=n;i++)
F[i]=F[i-1]+F[i-2];
return F[n];//直接调用
}
int main()
{
cout<<Fib(6)<<endl;
return 0;
}
使用情形:
1、选择/不选择,求最优解(2维dp)以下试题按照难以程度升序排列
问题描述
给定N个物品,每个物品有一个重量W和一个价值V.你有一个能装M重量的背包.问怎么装使得所装价值最大.每个物品只有一个.
输入格式
输入的第一行包含两个整数n, m,分别表示物品的个数和背包能装重量。
以后N行每行两个数Wi和Vi,表示物品的重量和价值
输出格式
输出1行,包含一个整数,表示最大价值。
样例输入
3 5
2 3
3 5
4 7
样例输出
8
数据规模和约定
1<=N<=200,M<=5000.
#include
using namespace std;
int W[5004];
int Vi[5004];
int dp[5004][5004];//动态规划
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>W[i]>>Vi[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dp[i][j]=dp[i-1][j];
if(j>=W[i]){
dp[i][j]=max(dp[i][j],dp[i-1][j-W[i]]+Vi[i]);//
}
}
}
cout<<dp[n][m];//最大价值
return 0;
}
问题描述
小D接到一项任务,要求他爬到一座n层大厦的顶端与神秘人物会面。这座大厦有一个神奇的特点,每层的高度都不一样,同时,小D也拥有一项特殊能力,可以一次向上跳跃一层或两层,但是这项能力无法连续使用。已知向上1高度消耗的时间为1,跳跃不消耗时间。由于事态紧急,小D想知道他最少需要多少时间到达顶层。
输入格式
第一行包含一个整数n,代表楼的高度。
接下来n行每行一个整数ai,代表i层的楼层高度(ai <= 100)。
输出格式
输出1行,包含一个整数,表示所需的最短时间。
样例输入
5
3
5
1
8
4
样例输出
1
数据规模和约定
对20%的数据,n<=10
对40%的数据,n<=100
对60%的数据,n<=5000
对100%的数据,n<=10000
#include
using namespace std;
int main(){
int n;
cin>>n;
int ai[10005];
for(int i=1;i<=n;i++){
cin>>ai[i];
}
int dp[10005][2];//动态规划二维dp[每层楼][每层楼的选择0爬,1跳]
memset(dp,0,sizeof(dp));
dp[1][0]=ai[1];//初始化,第一层选择爬的情况
dp[1][1]=0;//第一层选择跳的情况
for(int i=2;i<=n;i++){
dp[i][0]=min(dp[i-1][0],dp[i-1][1])+ai[i];//如果选择爬的话,那么之前一层可以是爬,也可以是跳上来的
dp[i][1]=min(dp[i-1][0],dp[i-2][0]);//如果是使用超能力,那么之前的一层/两层必须是爬上来的
}
cout<<min(dp[n][0],dp[n][1])<<endl;//选择最终耗时最短的方法
return 0;
}
问题描述 有一条长为n的走廊,小明站在走廊的一端,每次可以跳过不超过p格,每格都有一个权值wi。 小明要从一端跳到另一端,不能回跳,正好跳t次,请问他跳过的方格的权值和最大是多少?
输入格式 输入的第一行包含两个整数n, p, t,表示走廊的长度,小明每次跳跃的最长距离和小明跳的次数。 接下来n个整数,表示走廊每个位置的权值。
输出格式 输出一个整数。表示小明跳过的方格的权值和的最大值。
样例输入 8 5 3 3 4 -1 -100 1 8 7 6
样例输出 12
数据规模和约定 1<=n, p, t<=1000, -1000<=wi<=1000。
#include
using namespace std;
const long long int inf=0x3f3f3f;
int main(){
long long int n,p,t;
cin>>n>>p>>t;
long long int dp[1005][1005]; //当前格,当前跳的最大权值和
long long int wi[1005];
for(int i=1;i<=n;i++){//输入每一格距离的权值
cin>>wi[i];
}
if(n>p*t){
n=p*t;//划定距离,使其在跳跃能力范围内
}
for(int i=n;i>=n-p&&i>=0;i--){//动态规划的初始化,我们从最后开始,定义最后一步。
dp[i][1]=wi[i];//最后一格的最后一跳
}
for(int i=n;i>=0;i--){
for(int j=2;j<=t;j++){
dp[i][j]=-inf;
for(int k=1;k<=p&&i+k<=n;k++){
dp[i][j]=max(dp[i+k][j-1],dp[i][j]);
}
if(dp[i][j]!=-inf){
dp[i][j]+=wi[i];//如果找出步数内的最大值,那么加上自身的权值
}
}
}
cout<<dp[0][t]<<endl;
return 0;
}
问题描述
我的某室友学过素描,墙上有n张他的作品。这些作品都是宽度为1,高度不定的矩形,从左到右排成一排,且底边在同一水平线上。宿舍评比就要来了,为了及格,我们决定买不多于m块的矩形木板,把这些作品和谐掉。要求木板也从左到右排成一排,且底边与作品的底边在同一水平线上。在能够把所有作品和谐掉的前提下,我们希望这些木板的面积和最小,问最小面积和。
输入格式
第一行两个数n和m,表示作品数和木板数;
第二行n个数Hi,表示从左到右第i个作品的高度。
输出格式
一行一个数ans,表示答案。
样例输入
5 2
4 2 3 5 4
样例输出
22
数据规模和约定
对于30%的数据:1<=n,m<=10;
对于100%的数据:1<=n,m<=100,1<=Hi<=10000。
#include
#define INF 0x3f3f3f3f
using namespace std;
int main(){
int h[105];
int hmax[105][105];
int dp[105][105];
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>h[i];
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
hmax[i][j]=max(hmax[i][j-1],h[j]);
}
}
memset(dp,INF,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i][1]=i*hmax[1][i];
for(int j=2;j<=m;j++){
for(int k=1;k<=i-j+1;k++){
dp[i][j]=min(dp[i][j],dp[i-k][j-1]+k*hmax[i-k+1][i]);
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}
dfs:
一个很好的KMP总结
构建前缀表
void getNext_1(int *next,string s){
int j=0;
next[j]=0;
for(int i=1;i<s.size();i++){
while(j>0&&s[i]!=s[j]){
j=next[j-1];
}
if(s[i]==s[j]){
j++;
}
next[i]=j;
}
}
主函数调用
int main(){
string s;//需要匹配的字符
string s1;//被匹配的字符
cin>>s>>s1;
int next[s.size()];
getNext(next,s);
int j=0;
for(int i=0;i<s1.size();i++){
while(j>0&&s1[i]!=s[j]){
j=next[j-1];
}
if(s1[i]==s[j]){
j++;
}
if(j==s.size()){
cout<<s1<<"可以匹配"<<endl;
break;
}
}
return 0;
}
问题描述
给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行。你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符;当选项关闭时,表示同一个字母的大写和小写看作相同的字符。
输入格式
输入的第一行包含一个字符串S,由大小写英文字母组成。
第二行包含一个数字,表示大小写敏感的选项,当数字为0时表示大小写不敏感,当数字为1时表示大小写敏感。
第三行包含一个整数n,表示给出的文字的行数。
接下来n行,每行包含一个字符串,字符串由大小写英文字母组成,不含空格和其他字符。
输出格式
输出多行,每行包含一个字符串,按出现的顺序依次给出那些包含了字符串S的行。
样例输入
Hello 1 5 HelloWorld
HiHiHelloHiHi
GrepIsAGreatTool HELLO
HELLOisNOTHello
样例输出
HelloWorld
HiHiHelloHiHi
HELLOisNOTHello
样例说明
在上面的样例中,第四个字符串虽然也是Hello,但是大小写不正确。如果将输入的第二行改为0,则第四个字符串应该输出。 评测用例规模与约定
1<=n<=100,每个字符串的长度不超过100。
#include
using namespace std;
string s1[104];
string s;
void getNext_0(int *next,string s){
int j=0;
next[j]=0;
for(int i=1;i<s.size();i++){
char c1,c2;
c1=s[i]-'A'+'a';
c2=s[i]-'a'+'A';
while(j>0&&c1!=s[j]&&c2!=s[j]&&s[i]!=s[j]){
j=next[j-1];
}
if(s[i]==s[j]||c1==s[j]||c2==s[j]){
j++;
}
next[i]=j;
}
}
void getNext_1(int *next,string s){
int j=0;
next[j]=0;
for(int i=1;i<s.size();i++){
while(j>0&&s[i]!=s[j]){
j=next[j-1];
}
if(s[i]==s[j]){
j++;
}
next[i]=j;
}
}
int main(){
int num,n;
cin>>s>>n>>num;
for(int i=0;i<num;i++){
cin>>s1[i];
}
if(s.size()==0){
return 0;
}
int next[s.size()];
for(int k=0;k<num;k++){
string p=s1[k];
if(p.size()<s.size()){
continue;
}
if(n==0){//大小写不敏感
getNext_0(next,s);
int j=0;
for(int i=0;i<p.size();i++){
char c1,c2;
c1=p[i]-'A'+'a';
c2=p[i]-'a'+'A';
while(j>0&&p[i]!=s[j]&&c1!=s[j]&&c2!=s[j]){
j=next[j-1];
}
if(p[i]==s[j]||c1==s[j]||c2==s[j]){
j++;
}
if(j==s.size()){
cout<<p<<endl;
break;//这里加break很重要不然如果一个字符串中有其他匹配的就会一直输出。
}
}
}
if(n==1){//大小写敏感
getNext_1(next,s);
int j=0;
for(int i=0;i<p.size();i++){
while(j>0&&p[i]!=s[j]){
j=next[j-1];
}
if(p[i]==s[j]){
j++;
}
if(j==s.size()){
cout<<p<<endl;
break;
}
}
}
}
return 0;
}
【问题描述】
队列操作题。根据输入的操作命令,操作队列(1)入队、(2)出队并输出、(3)计算队中元素个数并输出。
输入格式
第一行一个数字N。
下面N行,每行第一个数字为操作命令(1)入队、(2)出队并输出、(3)计算队中元素个数并输出。
输出格式
若干行每行显示一个2或3命令的输出结果。注意:2.出队命令可能会出现空队出队(下溢),请输出“no”,并退出。
样例输入
7
1 19
1 56
2
3
2
3
2
样例输出
19
1
56
0
no
数据规模和约定
1<=N<=50
【思路】这里用到了queue(队列的STL容器)
定义一个queue的变量 queue<Type> Q
查看是否为空范例 Q.empty() 是的话返回1,不是返回0;
从已有元素后面增加元素 Q.push()
输出现有元素的个数 Q.size()
显示第一个元素 Q.front()
显示最后一个元素 Q.back()
清除第一个元素 Q.pop()
【注意】这里有个很顶的地方就是输出0后退出,就是漏了这个条件一直不能满分,这种编程题一定要看全!!!!
#include
#include
using namespace std;
queue<string> q;
int main(){
stringstream ss;
string s1;
int N,op;
string num;
int k=0;
cin>>N;
string a[N];
for(int i=0;i<N;i++){
cin>>op;
if(op==1){
cin>>num;
q.push(num);
}
if(op==2){
if(!q.empty()){
a[k++]=q.front();
q.pop();
}
else{
a[k++]="no";//请输出“no”,并退出。
break;
}
}
if(op==3){
ss<<q.size();
ss>>s1;
a[k++]=s1;
ss.clear();
}
}
for(int i=0;i<k;i++){
cout<<a[i]<<endl;
}
return 0;
}
[问题描述]
宁宁考虑的是这样一个问题:一个操作数序列,从1,2,一直到n(图示为1到3的情况),栈A的深度大于n。
现在可以进行两种操作,
1.将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的push操作)
2. 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的pop操作)
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由
1 2 3
生成序列
2 3 1
的过程。
(原始状态如上图所示)
你的程序将对给定的n,计算并输出由操作数序列1,2,…,n经过操作可能得到的输出序列的总数。
输入格式
输入文件只含一个整数n(1≤n≤18)
输出格式
输出文件只有一行,即可能输出序列的总数目
样例输入
3
样例输出
5
【思路】这里我用到了卡特兰数,有兴趣的话你也可以用数学归纳推一下。
(n个不同的元素进栈,出栈不同序列个数有(1/1+n)*C(n,2n))
#include
using namespace std;
int main(){
int n;
long long count;
cin>>n;
long long a=1;//分子
long long b=n+1;//分母
long long temp;
for(int i=0;i<n;i++){
temp=2*n-i;
a*=temp;
temp=n-i;
b*=temp;
while(a%2==0&&b%2==0){//因为数字很大,只能时间换空间,除二收益很大,得不出答案再除以5,【7 9 11……以此类推】
a/=2;
b/=2;
}
while(a%3==0&&b%3==0){
a/=3;
b/=3;
}
}
count=a/b;
cout<<count<<endl;
return 0;
}
[问题描述]
对于16进制,我们使用字母A-F来表示10及以上的数字。如法炮制,一直用到字母Z,就可以表示36进制。36进制中,A表示10,Z表示35,AA表示370你能算出
MANY 表示的数字用10进制表示是多少吗?
[答案提交]
1040254
#include
using namespace std;
int main(){
int num;
num=('m'-'a'+10)*pow(36,3)+
('a'-'a'+10)*pow(36,2)+
('n'-'a'+10)*36+
('y'-'a'+10);
cout<<num<<endl;
return 0;
}
[问题描述] 小明家的一面装饰墙原来是 310 的小方格。现在手头有一批刚好能盖住2个小方格的长方形瓷砖。瓷砖只有两种颜色:黄色和橙色。小明想知道,对于这么简陋的原料,可以贴出多少种不同的花样来。小明有个小小的强迫症:忍受不了任何22的小格子是同一种颜色。(瓷砖不能切割,不能重叠,也不能只铺一部分。另外,只考虑组合图案,请忽略瓷砖的拼缝)显然,对于 23 个小格子来说,口算都可以知道:一共10种贴法,如【p1.png所示】但对于 310 的格子呢?肯定是个不小的数目,请你利用计算机的威力算出该数字。
[答案提交]
在这里插入代码片
[问题描述]
x星球的钞票的面额只有:100元,5元,2元,1元,共4种。 小明去x星旅游,他手里只有2张100元的x星币,太不方便,恰好路过x星银行就去换零钱。小明有点强迫症,他坚持要求200元换出的零钞中2元的张数刚好是1元的张数的10倍, 剩下的当然都是5元面额的。银行的工作人员有点为难,你能帮助算出:在满足小明要求的前提下,最少要换给他多少张钞票吗? (5元,2元,1元面额的必须都有,不能是0)
[答案提交]
74
#include
using namespace std;
int main(){
for(int i=1;i<10;i++){
int num,sum;
num=200-21*i;
num=num/5;
if(num*5+21*i==200){
sum=11*i+num;
cout<<sum<<endl;
}
}
return 0;
}
[问题描述]
x星球的盛大节日为增加气氛,用30台机光器一字排开,向太空中打出光柱。安装调试的时候才发现,不知什么原因,相邻的两台激光器不能同时打开!国王很想知道,在目前这种bug存在的情况下,一共能打出多少种激光效果?显然,如果只有3台机器,一共可以成5种样式,即:
全都关上(sorry, 此时无声胜有声,这也算一种) 开一台,共3种 开两台,只1种, 30台就不好算了,国王只好请你帮忙了。要求提交一个整数,表示30台激光器能形成的样式种数。
[答案提交]
2178309
#include
using namespace std;
int main(){
int dp[30][2];//30盏灯每盏都可以有两种状态选择
dp[0][0]=1;
dp[0][1]=1;//为第一盏灯初始化
for(int i=1;i<30;i++){
dp[i][0]=dp[i-1][0]+dp[i-1][1];//如果当前灯是灭的它前一盏灯可以亮也可以不亮
dp[i][1]=dp[i-1][0];//当前灯如果要是亮的,前一盏灯就得是灭的
}
cout<<dp[29][0]+dp[29][1]<<endl;
return 0;
}
[问题描述] 小明想找到两个正整数X和Y,满足 ●2019
[答案提交]
7020
#include
using namespace std;
int main(){
bool flag=true;
int x=2020;
int num1,num2;
while(flag){
num1=2*x*x-2019*2019;
num2=sqrt(num1);
if(num2*num2==num1){
cout<<num2+x<<endl;
flag=false;
}
x++;
}
}
[问题描述] 将2019拆分为若千个两两不同的质数之和,一共有多少种不同的方法?
注意交换顺序视为同一种方法,例如2+ 2017= 2019与2017 +2= 2019视为同一种方法。
[答案提交]
55965365465060
解析:
这是一个jave关于这道题的解析,里面的一张图示我觉得超赞就摘录了
#include
#include
using namespace std;
//找出2019中(2-2019每个数字中有几个质数,选择或者不选择)
bool fun(int n){
for(int i=2;i<=sqrt(n);i++){
if(n%i==0){
return false;
}
}
return true;
}
int main(){
vector<int> V;
long long int dp[3000];
for(int i=2;i<=2019;i++){
if(fun(i)){
V.push_back(i);
}
}
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=0;i<V.size();i++){
for(int j=2019;j>=V[i];j--){
dp[j]=dp[j]+dp[j-V[i]];
}
}
cout<<dp[2019]<<endl;
return 0;
}
[问题描述] 小蓝特别喜欢2,今年是公元2020年,他特别高兴。他很好奇,在公元1年到公元2020年(包含)中,有多少个年份的数位中 包含数字2?
[答案提交]
563
#include
using namespace std;
int main(){
int q,b,s,g;
int ans=0;
for(int i=1;i<=2020;i++){
q=i/1000;
b=i%1000/100;
s=i%100/10;
g=i%10;
if(q==2||b==2||s==2||g==2){
ans++;
}
}
cout<<ans<<endl;
return 0;
}
[问题描述] 小蓝在一张无限大的特殊画布上作画。 这张画布可以看成一个方格图,每个格子可以用一个二维的整数坐标表示。小蓝在画布上首先点了一下几个点: (0,0), (2020, 11), (11, 14), (2000, 2000)。只有这几个格子上有黑色,其它位置都是白色的。 每过一分钟,黑色就会扩散一点。具体的,如果一个格子里面是黑色,它就会扩散到上、下、左、右四个相邻的格子中,使得这四个格子也变成黑色 (如果原来就是黑色,则还是黑色)。请问,经过2020分钟后,画布上有多少个格子是黑色的。
[答案提交]
20312088
#include
#include
#include
using namespace std;
int m[6100][6100];
int ans;
const int a=2021;
int fx[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
struct node{
int x,y;
int time;
};
void bfs(){
queue<node> Q;
m[0+a][0+a]=1;
m[2020+a][11+a]=1;
m[11+a][14+a]=1;
m[2000+a][2000+a]=1;
node n1,n2,n3,n4;
n1.x=0+a;n1.y=0+a;n1.time=0;
Q.push(n1);
n2.x=2020+a;n2.y=11+a;n2.time=0;
Q.push(n2);
n3.x=11+a;n3.y=14+a;n3.time=0;
Q.push(n3);
n4.x=2000+a;n4.y=2000+a;n4.time=0;
Q.push(n4);
ans=4;
node temp,next;
while(!Q.empty()){
temp=Q.front();
Q.pop();
if(temp.time==2020){
cout<<ans<<endl;
return;
}
for(int i=0;i<4;i++){
next.x=temp.x+fx[i][0];
next.y=temp.y+fx[i][1];
if(!m[next.x][next.y]){
ans++;
next.time=temp.time+1;
m[next.x][next.y]=1;
Q.push(next);
}
}
}
}
int main(){
memset(m,0,sizeof(m));
bfs();
return 0;
}
[问题描述] 定义阶乘n!= 1x2x3x…Xn。
请问100! (100 的阶乘)有多少个正约数。
[答案提交]
39001250856960000
#include
using namespace std;
int num_1[105];
int main(){
long long int sum=1;
memset(num_1,0,sizeof(num_1));
for(int i=2;i<=100;i++){
int num=i;
for(int j=2;j<=sqrt(i);j++){
while(num%j==0){
num_1[j]++;
num=num/j;
}
}
if(num>1){
num_1[num]++;
}
}
for(int i=2;i<=100;i++){
if(num_1[i]!=0){
sum=sum*(num_1[i]+1);
}
}
cout<<sum<<endl;
}
【问题描述】
小蓝特别喜欢单调递增的事物。
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
例如,在字符串 lanqiao 中,如果取出字符 n 和 q,则 nq 组成一个单调递增子序列。类似的单调递增子序列还有 lnq、i、ano 等等。
小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝认为他们并没有本质不同。
对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个?
例如,对于字符串 lanqiao,本质不同的递增子序列有 21 个。它们分别是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、anq、lno、ano、aio。
请问对于以下字符串(共 200 个小写英文字母,分四行显示):
tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl
本质不同的递增子序列有多少个?
[答案提交]
3616159
#include
#include
#include
#include
using namespace std;
string s;
int main()
{
cin>>s;
int dp[220];
for(int i=0;i<s.size();++i){
dp[i] = 1;
}
for(int i=1;i<s.size();++i){
for(int j=0;j<i;++j){
if(s[i]==s[j]){
dp[i]-=dp[j];
}
if(s[i]>s[j]){
dp[i] += dp[j];
}
}
}
cout<<accumulate(dp,dp+s.size(),0);
return 0;
}