- 写在前面
- 第一场
- 7-2 签到题
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- 我的代码
- 总结
- 问题分析
- lowbit函数
- 7-6 dh与学妹过桥
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码
- 总结
- 解题思路
- 7-7 有多少个质数
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- 我的代码
- AC代码
- 总结:
- 问题分析:
- 埃氏筛
- 7-8 天上也会掉馅饼
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码
- 总结
- 解题思路
- 7-9 遍遍遍历
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码1
- AC代码2
- 总结
- 解题思路
- 7-10 无间道
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- 我的代码(不是正确的代码)
- AC代码
- 总结
- 问题分析
- 解题思路
- 7-11 简单的图
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码
- 总结
- 解题思路
- 第二场
- 7-6 YooQ和olderciyuan玩石子
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码
- 总结
- 问题分析
- 解题思路
- 注意
- 7-7 霸道
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码
- 总结
- 问题分析
- 解题思路
- 注意
- 7-9 WaWa机
- 题目内容
- 输入格式
- 输出格式:
- 输入样例:
- 输出样例
- AC代码
- 总结
- 问题分析
- 解题思路
- 写在后面
如果有佬发现文章中有任何问题(包括但不限于引用题目以及码的佬的文章的版权问题),欢迎随时踢我。
第一场第一场共11题,AC6题,其中有一题数据不是特别完善,被我钻了空子。涉及知识点:位运算、 dp、 数论、 模拟、 二叉树、 图的构建
7-2 签到题 题目内容小明和小东是生活在二进制世界的人,一天他们分别获得了一个十进制数,他们想通过将该十进制数分解成二进制数,然后取出其二进制下最小非零数值的部分进行比较,如果小明的更小那么输出"xiaoming",如果小东的更小输入“xiaodong”,如果一样小输出“same”。
输入格式第一行输入一个整数 1≤t≤1000 , 代表测试数据的组数。
每组数据输入一行,每行两个正整数 x,y ,x是小明获得的数 , y是小东获得的数 .
保证所有输入数据 1≤x,y≤1e18.
输出格式:参考题意输出格式即可。
输入样例:2
1 1
2 1
same
xiaodong
#includeusing namespace std;
#define int long long
signed main()
{int t;
cin>>t;
while(t--)
{long long a,b;
long long ma=0,mb=0,x=0,y=0;
cin>>a>>b;
while(a)//计算数字a中出现第一个1前有多少个0
{ma=a%2;//用十进制转二进制的方法取末位
a/=2;
if(ma==0)
x++;
else
break;
}
while(b)//计算数字b中出现第一个1前有多少个0
{mb=b%2;
b/=2;
if(mb==0)
y++;
else
break;
}
if(x==y)
cout<<"same"<<'\n';
else if(x>y)
{cout<<"xiaodong"<<'\n';
}
else
cout<<"xiaoming"<<'\n';
}
return 0;
}
总结
问题分析这题我练习的时候花了很多时间,主要是对“其二进制下最小非零数值的部分”的理解花了很长时间。在网上冲浪的时候,发现有一个叫lowbit()的函数能处理这个题目。
lowbit函数lowbit(x)的值是x的二进制表达式中最低位的1所对应的十进制值,简单来说,lowbit(x)是将 x 转化成二进制数之后,只保留最低位(从右往左数,第一位)的1及其后面的0,截断前面的内容,然后再转成10进制数。
举个栗子🌰,lowbit(6)=2
代码码在这
int lowbit(int x)
{return x&(-x);
}
有个佬的总结挺好的,我就不赘述了,链接码在这
https://blog.csdn.net/weixin_44694201/article/details/118034246
注:
1:lowbit(x)不是一个封装好的函数,要自己手搓
2:lowbit(x)有几种不同的写法,比较推荐上面这种,容易理解
吃完饭后dh和学妹一起走到了一条江边,有两列平行的石墩桥,每个石墩上都有一个小写字母,dh对学妹说:我走上面这列石墩,你走下面的石墩,我先走一个石墩然后你在你那列石墩跟着我走一个同样字母的石墩,一直向前走,直到过了这条河,你知道你最多能踩多少个石墩吗?你答的出来吗?
输入格式输出两行字符串,表示两列石墩桥(字符串长度大不超过1000)
输出格式:输出一个整数,表示最多走多少个石墩
输入样例:abcdef
acebeee
3
AC代码#includeusing namespace std;
const int N =1e3+5;
#define int long long
char a[N],b[N];
int f[N][N];
signed main()
{scanf("%s%s",a,b);
for (int i = 0;i< strlen(a); i ++)
for (int j = 0; j< strlen(b); j ++)
{if (a[i] == b[j]) f[i + 1][j + 1] = f[i][j] + 1;
else f[i + 1][j + 1] = max(f[i][j + 1], f[i + 1][j]);
}
cout<< f[strlen(a)][strlen(b)]<< endl;
return 0;
}
总结这题我写错了,后面借助网络的力量,发现理解错题目了。dh走一步,学妹不一定要走到dh站的石墩上的字母上,抽象一下就是典型的dp最长公共子序列(LCS)。
这里也把佬的总结码在这
https://blog.csdn.net/qq_62362934/article/details/125919681
注:佬的总结跟我的有点不一样
解题思路1.设计状态(定义一个数组,确定其各维含义)
i表示当dh走到a的i位置,j表示学妹走到b的j位置,f[i][j]表示dh走到a的i位置,学妹走到b的j位置时,学妹走的石墩数。其中学妹走过的石墩上的字母,即为a的最长公共子序列,f[i][j]表示最长公共子序列的长度。
2.状态转移方程(类似于数学归纳法,由前面的数据根据一定的关系推出后面的数据)
1)如果有某一个字符串为空的话,f[i][j]=0,在这个是全局变量,初始化为0,不用特别考虑
2)如果a[i]=b[j],那么dh走一步,学妹也走一步,最长公共子序列的长度可以在原来的基础上+1,表示为:
if(a[i]==b[i]) f[i+1][j+1] = f[i][j - 1] + 1;
3)如果a[i]!=b[j],这时有两种选择,要么dh走一步,要么学妹走一步,又要求大,那么表示为:
f[i + 1][j + 1] = max(f[i][j + 1], f[i + 1][j]);
3.找出初始值
这里是全局变量,初始化为0。
7-7 有多少个质数 题目内容给一个正整数 n ,你需要求出 1,2,3,…,n 这 n 个数字有多少个是质数。
质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
在一行中给出一个正整数 n (1<=n<=30,000,000)
输出格式:在一行中输出一个数字,表示 1,2,3,…,n 有多少个数字是质数。
输入样例:10
输出样例4
我的代码#includeusing namespace std;
#define int long long
int n,sum;
int jugde(int x)
{if(x<2)
return 0;
if(x==2||x==3)
return 1;
if(x%4!=1&&x%4!=3)
return 0;
for(int i=3; i*i<=x; i+=4)
{if(x%i==0||x%(i+2)==0)
return 0;
}
return 1;
}
signed main()
{cin>>n;
for(int i=2;i<=n;i++)
{if(jugde(i))
sum++;
}
cout<
AC代码#includeusing namespace std;
const int maxn=3e7+5;
bool su[maxn];
int primer[maxn];
int main()
{int n,sum=0;
cin>>n;
su[0]=su[1]=true;
for(int i=2;i<=n;i++)
{if(!su[i])
{primer[sum++]=i;
for(int j=2*i;j<=n;j+=i)
su[j]=true;
}
}
cout<
总结:
问题分析:我用的是四倍筛,练习的时候还不知道埃氏筛,有两个测试点运行超时。
埃氏筛主要原理:把已经判断过的素数存到primer中,并把素数的倍数全部标记成非素数。
这里也码一个佬对素数筛的总结
https://blog.csdn.net/Yuki_fx/article/details/115103663
注:如果两个数组都开成int的话内存超限,bool只占一个字节,而int占四个字节,这里bool数组也可以用char数组代替。
7-8 天上也会掉馅饼 题目内容众所周知,天上是不会掉馅饼的。可是有一天,在一座城市的上空,一架装满馅饼的运输机在高空遇到了强烈的气流,为了保证运输机的安全,机长决定将一部分馅饼分散空投于某座小镇中。在小镇中的小明第一时间发现了天上在掉馅饼,于是他急忙准备接馅饼,他希望能尽可能多地接到馅饼。
小明当前位于一条道路之上,他可以从所在道路任意一点开始(从 0 秒开始),道路长度为 d 米(即可行走区域为[1,d])。天上一共会掉落 n 个馅饼,每个馅饼将于 t 秒后掉落于道路 x 米处,小明每一秒可以选择留在原地或者向前或者向后移动 1 米,求小明最多可接到多少馅饼?
由于小明也是个讲卫生的人,所以他并不会捡起掉在地上的馅饼。
这里我们将“能接到馅饼”定义为——当一个馅饼还有 0 秒掉到地面 x 米处时,如果小明此时正在该处,即可接到馅饼。
注意:可能会有多个馅饼在相同时间后落于同一地点。
输入格式第一行给出两个整数 d,n。
接下来的 n 行,每行两个整数 x 和 t,代表第 i 个馅饼的状态(具体含义见题面描述)。
输出格式:在一行中输出一个整数,为小明大可接到的馅饼数。
输入样例:10 6
3 1
2 2
1 3
5 3
6 4
7 5
4
AC代码#includeusing namespace std;
#define int long long
const int N=1e3+5;
int dp[N][N],a[N][N];
signed main(){int n,d,mxt=0,maxn=0;
cin>>d>>n;
for(int i=1;i<=n;i++)
{int x,t;
cin>>x>>t;;
a[t][x]++;
mxt=max(mxt,t);
}
for(int i=mxt;i>=0;i--)
{for(int j=1;j<=d;j++)
{dp[i][j]=max(max(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1])+a[i][j];
}
}
for(int j=1;j<=d;j++)//开始时小明的位置不确定,所以要比较小明在不同位置开始能接到的馅饼数
maxn=max(maxn,dp[0][j]);
cout<
总结这题我认为是一个典型数塔dp的一个小改编,这题的AC代码,是看了一个典型数塔dp题目的各种佬的文章,之后自己写的代码。
这里也码了我看过的文章
https://blog.csdn.net/qq_43765333/article/details/107100259
1.设计状态(定义一个数组,确定其各维含义)
i表示时间为i,j小明所在的位置,dp[i][j]表示i时间,小明j位置时,小明接到的馅饼的数量。
2.状态转移方程(类似于数学归纳法,由前面的状态,根据一定的关系推出后面的状态)
小明每次移动有三种情况:1)原地不动;2)前走一步;3)后走一步。只要把小明移动前接到的大馅饼数,加上移动后i时间掉在j位置上的馅饼数,就是小明在i时间,j位置上,接到的大馅饼数。
dp[i][j]=max(max(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1])+a[i][j];
3.找出初始值
这里是全局变量,初始化为0。
Keven这次遇到了一个大麻烦,题目大意是给你一个二叉树的前序遍历和中序遍历,输出它的后序遍历,这可难坏了Keven,还好Keven认识你,于是他向你请教了这个问题。
输入格式第一行一个数字,表示前序和中序序列的长度。
第二行一个字符串,表示它的前序遍历序列
第三行一个字符串,表示它的中序遍历序列。
保证字符串中只含有大写字母并且互不相等
输出格式:在一行中输出它的后序遍历。
输入样例:4
ABCD
BACD
BDCA
AC代码1#includeusing namespace std;
#define int long long
void retree(string a,string b)
{int t = b.find(a[0]);//找根节点在b中的位置
if (t != 0)//如果这个根节点还有叶节点
retree(a.substr(1, t), b.substr(0, t));//对左叶的树进行操作
if (b.size() >t + 1)//如果这个根节点有右子叶
retree(a.substr(t + 1), b.substr(t + 1));
cout<< a[0];//输出节点代表的信息
return ;
}
signed main()
{int n;
cin>>n;
string q,z;
cin>>q>>z;
retree(q,z);
cout<<'\n';
return 0;
}
AC代码2#include#includeusing namespace std;
#define int long long
struct TNode{char data;
TNode *lchild,*rchild;
};
typedef TNode *BinTree;
BinTree pre_mid_build(char* pre, char* mid, int num){if(pre==NULL||mid==NULL||num<=0)
return NULL;
BinTree root=new TNode;
root->data=pre[0];
root->lchild=NULL;root->rchild=NULL;
if(num==1) return root;
int left_num=0;//左子树结点总数
char* middle_root=mid;
while(*middle_root!=pre[0]&&middle_root<=(mid+num-1)){middle_root++;
left_num++;
}
if(left_num>0)//创建左子树
root->lchild=pre_mid_build(pre+1,mid,left_num);
if(num-left_num-1>0)//创建右子树
root->rchild=pre_mid_build(pre+left_num+1,mid+left_num+1,num-left_num-1);
return root;
}
void PostorderTraversal(BinTree T){//后序遍历
if(T) {PostorderTraversal(T->lchild);
PostorderTraversal(T->rchild);
cout<< T->data;
}
return ;
}
void DestroyBiTree(BinTree &T){//销毁二叉树
if(T) {DestroyBiTree(T->lchild);
DestroyBiTree(T->rchild);
delete T;
T = nullptr;
}
return ;
}
signed main(){int n;
cin>>n;
char pre[n+5];
char mid[n+5];
cin>>pre>>mid;
BinTree root=pre_mid_build(pre, mid, n);
PostorderTraversal(root);
DestroyBiTree(root);
cout<<'\n';
return 0;
}
总结这题本意应该是前序遍历和中序遍历重构二叉数,然后输出后序遍历。AC代码2就是这样写的,是我根据《数据机构》和佬的文章写的
佬的文章码在这
https://blog.csdn.net/weixin_65908362/article/details/127721109
我在网上冲浪的时候看到一个另一个佬的优化代码,我觉得很巧妙,这个AC代码1就是佬的代码。
佬的文章也码在这里
https://blog.csdn.net/qq_62658309/article/details/127742327
这题目的还是比较明确的,重构二叉树的递归思路是比较好找,就是码出来比较不容易。AC代码1直接看比较难理解,画出树,根据代码模拟,比较好理解。
7-10 无间道 题目内容Bear_2 发现春天花花幼儿园中出了内鬼。
如果一个人满足下面两个的条件,那么就可以认定他为内鬼:
1、所有人对他都是信任的
2、他对所有人都是不信任的
Bear_2 开始调查幼儿园的情况,他发现幼儿园中总共有 n 个人,他每调查出两个人的关系就会记到小本本上,现在共找出了 m 对关系,请问可以找到几个内鬼。
输入格式第一行给出两个正整数 n,m(1<=n,m<=10
6
) 分别表示春天花花幼儿园的人数和两人之间的关系。
之后的 m 行,每行给出两个正整数 a,b(1<=a,b<=n,a!=b) 表示 a 信任 b 。
由于 Bear_2 比较蠢可能会重复调查两个人的关系并且记录。
输出格式:第一行输出一个正整数 k 表示内鬼的数量。如果没有内鬼则输出 0
第二行从小到大输出 k 个正整数表示内鬼的编号。
3 5
1 2
1 3
2 1
2 3
2 1
1
3
#includeusing namespace std;
#define int long long
int a[1000005],b[1000005],c[1000005];
bool cmp(int a,int b)
{return aint n,m,k=0;
cin>>n>>m;
//a表示信任的人数,b表示被信任的人数
while(m--)
{int x,y;
cin>>x>>y;
a[x]++;
b[y]++;
}
for(int i=1;i<=n;i++)
{if(a[i]==0||b[i]==n)
c[k++]=i;
}
cout<
AC代码#includeusing namespace std;
#define int long long
set>s;//存n个人之间的关系,由于set中没有重复数据的特性,将重复数据过滤
setans;//把内奸的存起来,set中能自动排序
signed main()
{int n,m,q,sum=0;
cin>>n>>m;
vectorsum1(n+5,0);//sum1[i]表示i信任多少人
vectorsum2(n+5,0);//sum2[i]表示i被多少人信任
while(m--)
{int a,b;
cin>>a>>b;
s.insert({a,b});//因为有重复数据,所以不能在输入的时候直接计数
}
set>::iterator it1;//迭代器,用于遍历set
for(it1=s.begin();it1!=s.end();it1++)
{sum1[it1->first]++;
sum2[it1->second]++;
}
for(int i=1;i<=n;i++)
if(sum1[i]==0&&sum2[i]==n-1)//满足题目给出的内奸条件的,存入ans
{ans.insert(i);
sum++;
}
cout<::iterator it;
for(it=ans.begin();it!=ans.end();it++)
cout<<*it<<'\n';
return 0;
}
总结
问题分析我的代码虽然过了全部的测试点,但是不是正确的代码。我把题目的两个条件,理解成满足其一即可,而且我也没有处理重复记录的情况,只能说是撞大运了。
解题思路由题目的“由于 Bear_2 比较蠢可能会重复调查两个人的关系并且记录”,比较容易想到用set容器来实现去重,实现了去重的话,这个题目就没有其他难点了。答案存储也可以直接用数组来存储,数据本身就是有序的,但是不能直接输出,因为要先统计间谍的数量(如果有其他的方法欢迎随时踢我)。
7-11 简单的图 题目内容有一个 n 个点 m 条边的无向不一定联通图。现在 Bear_2 想知道一对点 (x,y) 和多少条边相连,也就是说共有多少条边连接点 x 或者点 y 。他一共会问 q 次,请你回答他的询问。
输入格式第一行给出两个正整数 n,m(1<=n,m<=10
6
)
之后的 m 行,每行给出两个正整数 u,v(1<=u,v<=n) 表示点 u 和点 v 之间有一条无向边。保证没有自环,但可能有重边。
之后的一行给出一个正整数 q(1<=q<=10
5
) 表示询问的次数
之后的 q 行,每行给出两个正整数 u,v(1<=x,y<=n) 表示询问点 x,y 和多少条边相连。
输出格式:对于每次询问在一行内输出一个正整数 k 表示有 k 条边和点 x,y 相连。
输入样例:4 5
1 2
1 3
2 3
2 4
2 1
5
1 2
1 3
1 4
2 3
2 4
5
4
4
5
4
#includeusing namespace std;
#define int long long
const int N=1e6+5;
vectortu[N];
map,int>c;
signed main()
{int n,m;
cin>>n>>m;
while(m--)
{int u,v;
cin>>u>>v;
tu[u].push_back(v);
tu[v].push_back(u);
c[{u,v}]++;
}
int k;
cin>>k;
while(k--)
{int x,y;
cin>>x>>y;
if(x==y)
cout<x,y}]-c[{y,x}]<<"\n";//c[{x,y}]和c[{y,x}]在图上表示相同的边,且都存在重复的情况
}
return 0;
}
总结
解题思路有佬说过,“图的难点就在图的构建”。我的代码是开了二维的vector,果不其然,内存超限。然后有佬分享了代码,这个AC代码是看了佬的代码之后写的,跟佬的有一点点不一样。
1)因为这个图是无向图,因为u ,v相连,所以u点到v点有边,v点到u点有边,在tu[u]中插入v,tu[v]中插入u,tu[i].size()表示tu[i]中有多少个元素,即i点有多少条边;
2)如果x,y相连,有的边会被计数两次,所以用c[{u,v}]来存u->v的边的数量
第二场共11题,AC6题,最后两题目前为止还不知道咋整。涉及知识点:字符串、模拟、逆元、快速幂、贪心、并查集
7-6 YooQ和olderciyuan玩石子 题目内容YooQ 和 olderciyuan 来到湘潭大学参(gong)加(费)比(lv)赛(you),湘潭大学的门口有很多堆石子,于是童心大起的两人玩起了堆石子游戏,他们想将 N 堆石子合成一堆,合并两堆的代价为两堆石头的数量和,那么现在问题来了, 如果才能以最小的代价合成石子?
输入格式第一行给出一个整数 T(1<=T<=10),代表共有 T 组输入数据。
接下来 T 行,每行给出一个一个整数 N(1<=N<=1e6),随后给出 N 个正整数 a1,a2,a3…an(1<=ai<=1e9),代表每堆石子的石子个数。
题目保证所有输入数据 N 的总和不超过 2e6 。
输出格式:对于每一组输入数据,输出一个整数,代表最小代价。
输入样例:3
1 1
3 1 2 3
3 1 1 1
0
9
5
#includeusing namespace std;
#define int long long
signed main()
{int t;
cin>>t;
while(t--)
{priority_queue,greater>q;//优先队列,top是最小值
int n,sum=0,sum1=0;
cin>>n;
while(n--)
{int x;
cin>>x;
q.push(x);
}
while(q.size()>1)//只剩一堆石子的时候结束循环
{sum=q.top();
q.pop();
sum=sum+q.top();
q.pop();
q.push(sum);//把石子合并后入队,并排序
sum1+=sum;
}
cout<
总结
问题分析这题比较明显,一眼贪心,把石子从小到大排序,先把小的合并。练习的时候,我排序后就直接合并,然后只过了少数测试点。快结束的时候,我才发现,合并了两堆石子后,形成了新的石子堆,要再次排序,将最小的两个合并。
注:
这里不建议每次合并后又用sort排序。因为快排在数据比较有序的情况下,时间复杂的堪比冒泡排序(O(n^2))。
这里有一个小技巧,有时候题目给的数据可能比较有序,但是,你又需要将它排序,你可以先把它打乱,然后再排序。这样可能会更快,洛谷这个题就是一个例子亲测直接用sort会T)
https://www.luogu.com.cn/problem/P1177
分析清楚之后,就比较容易了,可以用优先队列来实现。每次把队头的两个元素取出来,相加后,把它们的和入队,一直循环到只剩下一堆石子。
注意我一开始把优先队列定义在全局,导致每次运行后都把上一次的结果保留,浪费了很多时间来debug。
7-7 霸道 题目内容有道是先来后到,后来霸道。在青青草原排队吃饭,只要前面的人战斗力不如你,你就可以让他直接离开。新来的人会先赶走战斗力不如他的人,然后再开始排队。
Bear_2 拿到了一份排队的记录,有 n 个人来吃饭,按顺序将来店里吃饭的人编号为 1 到 n ,第 i 个人的战斗力为 Di 。每当排队人数大于 2 人时,队列的第一个人就可以吃到饭,然后离开。
请从小到大输出吃到饭的人物编号。
输入格式第一行给出一个正整数 n(1<=n<=1e5) ,表示来吃饭的人的数量之后的 n 行,第 i 行给出一个正整数Di(1<=Di<=1e9) 表示编号为 i 的人的战斗力
输出格式:第一行输出一个正整数表示吃到饭的人的数量 K
第二行从小到大输出 K 个正整数表示吃到饭的人的编号。(末尾没空格)
输入样例:7
5
4
3
6
7
1
1
2
1 5
#includeusing namespace std;
#define int long long
int n,i,j=1;
deque>q;
vectora(1e5+1,0);
signed main()
{cin>>n;
deque>::iterator it=q.end();
while(n--)
{++i;
int d;
cin>>d;
it=q.end()-1;
while(!q.empty()&&d>it->second)//要先判断队列是否为空
{q.pop_back();
it=q.end()-1;
}
q.push_back({i,d});
if(q.size()>=3)//队列中人数大于2时,第一个人吃饭
{it=q.begin();
a[j++]=it->first;//把第一个人的序号存到a中
q.pop_front();//把第一个元素弹出
}
}
cout<
总结
问题分析练习的时候一直段错误,我一开始以为是迭代器跑来跑去,后面用其他方法写的时候还是段错误。求助了一下佬,发现是while循环的条件逻辑上有问题。
解题思路因为这里要把武力值不如自己的人赶走,所以要用deque,选好容器后,就按题意模拟。要注意q.end()不是指向最后一个元素,而是最后一个元素的后一个位置,所以我让it=q.end()-1。
注意这里我控制输出格式用的是
for(int i=1;i
是一个小技巧,当满足[ ]中的条件为真,输出后面的字符,条件为假,输出前面的字符。
7-9 WaWa机 题目内容在学校 D 栋的一个小隔间里,隐藏着一个神奇的 WaWa 机。小隔间只有在星期天的时候才会开门!为什么叫 WaWa 机呢?因为在集训队的队员们囤积了一星期的 Wa 题次数后,能以去小隔间抓相同次数的 WaWa。 但是 YooQ 不想让大家拿走 WaWa,也就是说不能拿走 WaWa,只能抓个开心。
WaWa 机里有 N 个娃娃,从左到右依次摆放。每次抓取只能从左向右地将某个右边的 WaWa 抓取到左边,只有当“抓的 WaWa 的高度 + 当前经过 WaWa 的高度<= WaWa 机的高度”才能通过当前 WaWa,从而将这个 WaWa 抓取到左边。
队员们想把小的 WaWa 尽量挪到前面(也就是左边)。现在告诉你 N 个 WaWa 的摆放情况以及一个数 H,表示 WaWa 机的高度。
请你输出当队员们完成任务时,WaWa 机里的 WaWa 的高度序列。(从左到右)
输入格式在第一行中输入一个整数 T,表示有 T 组测试数据。(1<=T<=10)
接下来对于每组输入数据,先于第一行给出两个整数 N 和 H,N 表示有 N 个 WaWa,H 表示当前 WaWa 机的高度。(1<=N<=5e3,1<=H<=1e8)
再于第二行给出 N 个整数 a1,a2…an,ai表示原来 WaWa 机里面第 i 个 WaWa 的高度。(1<=ai<=H)
输出格式:对于每组数据,在一行中输出一行数字表示当队员们完成任务时,WaWa 机里的 WaWa 的高度序列。数字间以空格分割,且行末没有多余空格。
输入样例:3
8 10
5 1 2 9 2 8 5 2
5 10
4 5 3 2 1
5 8
7 6 5 4 2
1 2 5 9 2 2 8 5
1 2 3 4 5
7 2 6 5 4
#includeusing namespace std;
#define int long long
signed main()
{int t;
cin>>t;
while(t--)
{int n,h,flag=1;
cin>>n>>h;
int a[n+1];
for(int i=0;i>a[i];
while(flag)
{flag=0;
for(int j=n-1;j>0;j--)
{if(a[j]+a[j-1]<=h&&a[j]flag++;
swap(a[j],a[j-1]);
}
}
}
for(int i=0;i
总结
问题分析练习的时候被这个题目吓到了,可能脑子也不太清醒了。后面补题的时候,仔细看了一下,又求助了一下佬,发现是有点类似冒泡排序。
解题思路因为要把小的数字尽可能的放到前面,所以可以从最后一个wawa开始遍历,把相邻的可以交换位置的娃娃全部交换位置,这个算法的时间复杂的是O(n^2),果然超时了。
因为我每次循环都全部遍历,把能交换位置的相邻wawa全部交换,所以如果某次循环中,没有wawa交换了位置,那么说明现在的位置已经是最终结果了,这时候就可以跳出循环,所以我加了一个flag记录某次循环wawa交换位置的次数。
写在后面感觉我某些题目的方法不是特别好,如果有其他的解题方法,欢迎随时赐教。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
分享文章:寒假第一、二场合集-创新互联
文章转载:http://lswzjz.com/article/ediji.html