注:本博客为练习合集,会不定期更新。
目录
csp_201912_2_回收站选址 :
问题描述
问题分析
解题思路
通过题目可以发现,垃圾的坐标范围非常的大,用简单的二维数组根本无法实现存储的功能,但是,垃圾的数量非常的小,最大只有1e3。因此,这里考虑只存储垃圾的位置,这样使用一维数组,且数组的最大只需要开1000个即可。由于相邻的垃圾之间坐标的x和y有且仅有1个相同且,另一个相差1,对角线之间的x和y均相差1,这样可以很容易的判断相邻位置和对角线位置。最后再遍历一遍即可完成,复杂度为O(n^2),完全符合题目要求。
参考代码
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
struct position
{
int x;
int y;
int check;
int point;
};
position p[1010];
int main()
{
memset(p,0,sizeof(p));
int n;
cin>>n;
int ans[5];
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)
{
cin>>p[i].x>>p[i].y;
for(int j=1;j<i;j++)
{
if((p[j].x==p[i].x&&abs(p[j].y-p[i].y)==1)||(p[j].y==p[i].y&&abs(p[j].x-p[i].x)==1))
{
p[i].check++;
p[j].check++;
}
else if(abs(p[j].y-p[i].y)==1&&abs(p[j].x-p[i].x)==1)
{
p[i].point++;
p[j].point++;
}
else ;
}
}
for(int i=1;i<=n;i++)
{
if(p[i].check==4)
{
ans[p[i].point]++;
}
}
for(int i=0;i<=4;i++)
{
cout<<ans[i]<<endl;
}
return 0;
}
csp_201909_2_小明种苹果(续) :
问题描述
问题分析
解题思路
本题不是很难,虽然看上去环形比较的麻烦,但是其实,题目只要求统计连续3棵的掉落情况,实际上只有倒数第二和倒数第一棵树在统计时需要用到环形这个条件,完全可以特判。之后就是判断是否有果子掉落,也非常的简单,只需要判断再中间统计果子数量时,两次的数量是否相同即可。之后存储一下掉落果子的位置,遍历一下即可求出D和E。
参考代码
#include <iostream>
#include <cstring>
using namespace std;
int isdrop[1010];
int n,m;
int main()
{
memset(isdrop,0,sizeof(isdrop));
cin>>n;
int ans=0;
int drop=0;
int e=0;
for(int i=0;i<n;i++)
{
cin>>m;
int init;
cin>>init;
for(int j=1;j<m;j++)
{
int p;
cin>>p;
if(p<=0) init=init+p;
else if(p>0&&p!=init)
{
init=p;
if(isdrop[i]!=1) drop++;
isdrop[i]=1;
}
}
ans+=init;
}
for(int i=0;i<n;i++)
{
if(isdrop[i]==1&&isdrop[(i+1)%n]==1&&isdrop[(i+2)%n]==1) e++;
}
cout<<ans<<" "<<drop<<" "<<e<<endl;
return 0;
}
csp_201903_2_二十四点 :
问题描述
问题分析
解题思路
第二次做这个题了,第一次在考场上做的时候只得了10分,而且代码写的非常的难看。第二次做,仔细一看其实非常的简单,前20分直接可以白嫖,然后说到24点,涉及到字符串算式的处理问题,本题已经非常的简化了,只有一位数,因此非常的好做,直接判断字符是否属于‘0’-‘9’即可,不是的就是运算符。然后再用栈结构辅助(简单计算器的写法),将*和/运算的部分结果先算出,将整个式子转换为+相连的式子再求和判断即可。说实话不难,可能栈需要想一下,但是基本都是常规的操作。
参考代码
#include <iostream>
#include <stack>
#include <string>
using namespace std;
stack<int> s;
int n;
int main()
{
s.push(-10000);
cin>>n;
string str;
for(int i=1;i<=n;i++)
{
cin>>str;
int pre=0;
for(int j=0;j<str.length();j++)
{
if(str[j]>='0'&&str[j]<='9')
{
if(pre==2) s.push(-(str[j]-'0'));
else if(pre==3)
{
int t=s.top();
s.pop();
s.push((str[j]-'0')*t);
}
else if(pre==4)
{
int t=s.top();
s.pop();
s.push(t/(str[j]-'0'));
}
else s.push(str[j]-'0');
}
else
{
if(str[j]=='+') pre=1;
else if(str[j]=='-') pre=2;
else if(str[j]=='x') pre=3;
else pre=4;
}
}
int ans=0;
while(s.top()!=-10000)
{
ans+=s.top();
s.pop();
}
if(ans==24) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
csp_201809_2_买菜 :
问题描述
小H和小W来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买n种菜,所以也都要装n次车。具体的,对于小H来说有n个不相交的时间段[a1,b1],[a2,b2]…[an,bn]在装车,对于小W来说有n个不相交的时间段[c1,d1],[c2,d2]…[cn,dn]在装车。其中,一个时间段[s, t]表示的是从时刻s到时刻t这段时间,时长为t-s。
由于他们是好朋友,他们都在广场上装车的时候会聊天,他们想知道他们可以聊多长时间。
输入的第一行包含一个正整数n,表示时间段的数量。
接下来n行每行两个数ai,bi,描述小H的各个装车的时间段。
接下来n行每行两个数ci,di,描述小W的各个装车的时间段。
输出一行,一个正整数,表示两人可以聊多长时间。
问题分析
解题思路
求若干时间段的交集的段长总和,思路是首先标记所有段,即用数组表示时间轴,将两人装货的时间段标记为1,离开的时间标为2,当且仅当两人在同一时间标记值都为1且之前未开始谈话时,两人才有可能谈话,在谈话的过程中,当遇到有一人离开或者两人都离开的时候终止计时,其余时刻计时+1。遍历后输出最后的计时总和即可。
参考代码
#include <iostream>
#include <cstring>
using namespace std;
int H[1000010];
int W[1000010];
int n;
int a,b;
int get_ans()
{
int get_start=0;
int start_tag=0;
int ans=0;
for(int i=1;i<1000010;i++)
{
if(get_start==0&&H[i]==1&&W[i]==1)
{
get_start=1;
}
else if(get_start==1&&H[i]!=0&&W[i]!=0)
{
if(H[i]==1&&W[i]==1) ans++;
else
{
ans++;
get_start=0;
}
}
else get_start=0;
}
return ans;
}
int main()
{
memset(H,0,sizeof(H));
memset(W,0,sizeof(W));
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a>>b;
for(int j=a;j<b;j++)
{
H[j]=1;
}
H[b]=2;
}
for(int i=1;i<=n;i++)
{
cin>>a>>b;
for(int j=a;j<b;j++)
{
W[j]=1;
}
W[b]=2;
}
cout<<get_ans()<<endl;
return 0;
}
csp_201803_2_碰撞的小球 :
问题描述
数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处。有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒。
当小球到达线段的端点(左端点或右端点)的时候,会立即向相反的方向移动,速度大小仍然为原来大小。
当两个小球撞到一起的时候,两个小球会分别向与自己原来移动的方向相反的方向,以原来的速度大小继续移动。
现在,告诉你线段的长度L,小球数量n,以及n个小球的初始位置,请你计算t秒之后,各个小球的位置。
因为所有小球的初始位置都为偶数,而且线段的长度为偶数,可以证明,不会有三个小球同时相撞,小球到达线段端点以及小球之间的碰撞时刻均为整数。
同时也可以证明两个小球发生碰撞的位置一定是整数(但不一定是偶数)。
输入的第一行包含三个整数n, L, t,用空格分隔,分别表示小球的个数、线段长度和你需要计算t秒之后小球的位置。
第二行包含n个整数a1, a2, …, an,用空格分隔,表示初始时刻n个小球的位置。
输出一行包含n个整数,用空格分隔,第i个整数代表初始时刻位于ai的小球,在t秒之后的位置。
对于所有评测用例,1 ≤ n ≤ 100,1 ≤ t ≤ 100,2 ≤ L ≤ 1000,0 < ai < L。L为偶数。
保证所有小球的初始位置互不相同且均为偶数。
问题分析
解题思路
本题已经做了简化,已经说明了小球的位置均为整数且碰撞的位置也为整数。而且,从数据规模上来看,小球数和迭代数均不超过10^2,因此,简单的暴力方法也是可取的,O(n3)的复杂度对于这个数据规模是可以接受的。总之,就是首先记录每一个小球的初始位置和初始方向,每一次迭代都使小球在其前进方向上增加一个单位,然后判断,如果发现小球已经到达了线段的端点,那么就改变小球的方向为相反的方向,如果没有,则寻找是否有与当前小球处于同一位置的小球,如果有的话,使两者均反向即可。最后输出每个小球的位置即可完成。很简单的一道题。
参考代码
#include <iostream>
#include <cstring>
using namespace std;
int n,l,t;
int pos[105];
int fx[105];
int main()
{
memset(pos,-1,sizeof(pos));
for(int i=0;i<105;i++)
fx[i]=1;
cin>>n>>l>>t;
for(int i=1;i<=n;i++)
{
cin>>pos[i];
}
for(int i=1;i<=t;i++)
{
for(int j=1;j<=n;j++)
{
if(fx[j]==1) pos[j]++;
else pos[j]--;
if(pos[j]==l||pos[j]==0)
{
fx[j]=-fx[j];
}
else
{
for(int k=1;k<=n;k++)
{
if(pos[k]==pos[j]&&k!=j)
{
fx[j]=-fx[j];
fx[k]=-fx[k];
break;
}
}
}
}
}
for(int i=1;i<=n;i++)
{
cout<<pos[i]<<" ";
}
cout<<endl;
return 0;
}
csp_202006_2_稀疏向量 :
问题描述
问题分析
解题思路
这个题和上次的19年12月的第二题有异曲同工之处,都是数据范围非常大,简单开数组无法存储所有数据,但是有效数据数量比较少。因此思路也与上次的相同,只存有效数据即可。同时,题目中给出的输入顺序是有序的,因此,也进一步的简化了这个题的难度。在求内积的时候,以一个向量为基准遍历所有有效数据,在第二个向量中只需要遍历上一次遍历的终点到新有效数据的这个范围内的点即可。时间复杂度为O(n*m),2秒的时间内完全可以完成。
参考代码
#include <iostream>
using namespace std;
int v1[500010][2];
int v2[500010][2];
int n,a,b;
int main()
{
cin>>n>>a>>b;
for(int i=1;i<=a;i++)
{
cin>>v1[i][0]>>v1[i][1];
}
for(int i=1;i<=b;i++)
{
cin>>v2[i][0]>>v2[i][1];
}
long long ans=0;
int j=1;
for(int i=1;i<=a;i++)
{
int ed=v1[i][0];
for(j;;j++)
{
if(v2[j][0]==ed)
{
//cout<<"position:"<<ed<<" j:"<<j<<" add:"<<v1[i][1]*v2[j][1]<<endl;
ans+=v1[i][1]*v2[j][1];
break;
}
else if(v2[j][0]>ed||j>b)
{
break;
}
else ;
}
}
cout<<ans<<endl;
return 0;
}