2020年1月9日凉心的比赛(一)

比赛链接

A - 最小的二进制数

题意:给你一串字符,它满足没有前导0,并且这个字符串由‘0’,‘1’组成(只有0或者1也行),这样的字符串称为正确的,现在我们可以做这两种操作,1:交换任意一对相邻的字符(“101” → “110”)2.两个‘1’可以合成为一个‘1’如(“110” → “10”)。

解法:找规律,如果没有‘1’的直接输出字符串就可以,其他的情况写几组可以发现,不管有奇数个‘1’还是偶数个,最终操作完之后就只有一个‘1‘且可以移动到最左端。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
	int n;
	char a[101];
	cin>>n;
	scanf("%s",a);
	int ans=0,k,m,w=0;
	for(int i=0;i<n;i++)
	{
		if(a[i]=='1')
		ans++;
		else
		w++;
	}
	if(ans==0)
	cout<<a;
	else   {
			 cout<<'1';
			 for(int j=1;j<=w;j++)
			 cout<<'0';
			 printf("\n");
	
}
}

B - 线段的包含关系

题意:给你几个一维线段的左右端点,线段的序号为1~n,你只需要找到其中的一组线段i,j(1<=i,j<=n),满足得线段ai位于线段aj内。
部分[l1, r1]位于部分[l2, r2] 的要求是l1 ≥ l2和r1 ≤ r2.

解法:定义一个结构体包含左端点、有端点、对应的序号(不然排序之后不知道对应的是谁了)然后再定义快排规则,如果左端点不等的话则按左端点从小到大排(因为左端点越小它包的范围越大),反之则按右端点从大到小排,然后a[i-1]的左端点一定满足小于等于a[i]的左端点,如果再满足a[i-1]的右端点大于等于a[i]的则a[i]一定位于线段a[i-1]内(这一块是问的王锐,我写的判断的代码老错,有空再查一查哪错了)

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct p{
	int x;
	int y;
	int q;//是用来记录对应的是哪个线段的
}a[300010];
bool cmp(p q,p w)
{
    if(q.x!=w.x)
    return q.x<w.x;
    else
    return q.y>w.y;
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
	cin>>a[i].x>>a[i].y;
	a[i].q=i;
}
	sort(a+1,a+1+n,cmp);
	int i;
	for(int i=2;i<=n;i++){
	   if(a[i].y<=a[i-1].y){
	     cout<<a[i].q<<' '<<a[i-1].q;
	     return 0;//它就直接代表程序结束了,不往下走了 
	 }
}
  cout<<-1<<' '<<-1;
}

错误的代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct p{
	int x;
	int y;
	int q;
}a[300010];
bool cmp(p q,p w)
{
    if(q.x!=w.x)
    return q.x<w.x;
    else
    return q.y>w.y;
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
	cin>>a[i].x>>a[i].y;
	a[i].q=i;
}
	sort(a+1,a+1+n,cmp);
	int index=1,m=0;//这一块往下有问题 
	while(index!=n){
		int i;
	for( i=1;i<=n;i++)
	{
		if(a[index].y>=a[i].y&&a[index].x<=a[i].x){
			if(index!=i){
		cout<<a[i].q<<' '<<a[index].q;
		m=1;
		break;
	}
	else
	continue;
	}
	 }
	 if(i!=n)
	 break;
	 else
	 index++;
}
if(m==0)
cout<<-1<<' '<<-1; 
	
 } 

C - 地下城还有劳拉

题意:给你n行m列,还有一个步数k,一个人从(1,1)开始,问你m步后他走到哪里(0<=k<n*m)

解法:就根据给出的已知条件的4行3列找规律,因为从(1,1)开始的,所以往下走(n-1)步会走到头,所以如果k<=n-1会按直线往下走,再往后找规律的话发现不好找,我们让他再接着往右走一步,即正好到了(n,2)即(k=n)这又是一种情况,其他情况就是(k>n)就有规律了(此时这个人是从(n,2)为起点开始的),设a=(k-n)%(m-1),b=(k-n)/(m-1),,这时可以发现如果(k-n)/(m-1)为偶数,那么她会往上走b步并且往纵坐标向右移动a步,最终就是(n-b,2+a),若为奇数则横坐标同理还是上移b步,纵坐标从m开始向左移动a步,最终就是(n-b,m-a)

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
	long long n,m,k;
    cin>>n>>m>>k;
	if(k<=n-1)
	cout<<1+k<<' '<<1;
	else if(k==n)
	cout<<n<<' '<<2; 
	else if(k>n)
	{
	long long a,b; 
	 a=(k-n)%(m-1);
	b=(k-n)/(m-1);
	if(b%2==0)
	cout<<n-b<<' '<<2+a;
	else
	cout<<n-b<<' '<<m-a;
	}}

D - 心火牧日常计算

E - 法法在分配工作

题意:就是找公因数个数

代码:

 #include<iostream>
#include<cstdio>
using namespace std;
int main()
{
	int n,i,sum=0;
	cin>>n;
	for(i=1;i<n;i++)
	{
	if(n%i==0)
	sum++;
}
printf("%d\n",sum);
}

F - 法法要穿过大门

题意:就是一个人从原点(0,0)开始走,每次可以往上走一步或者往右走一步,只要他走过y=x这个边界则要付一枚银币。

解法:一开始我想记录每个点的横纵坐标然后通过纵坐标与横坐标比值是否大于一来判断,正解是先判断是否走到边界,然后如果到边界的这次走法与一下步的走法相同,那么一定走过边间,若走法不同则一定过不了边界。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
   int n,sum=0,x=0,y=0;
   char s[100010];
   cin>>n;
  getchar(); 
   scanf("%s",s);
   for(int i=0;i<n;i++)
   {    
       if(s[i]=='U')
       y++;
       else
       x++;
       if(x==y&&s[i]==s[i+1])
       sum++;
   }
   printf("%d\n",sum);
}
   

G - 法法非法是朋友

题意:要从大圆中找到找一个小圆使某一个点不在小圆中而且大圆未被小圆包含的面积最小,求这个小圆的圆心,为此我们要分情况:
1.点在圆外,那么直接让小圆的圆心等于大圆的,两个圆重合即可。
2.点在圆内且该点与大圆圆心重合,那么画画图可知,极限就是在大圆内找一个半径为2/R的与大圆内切的小圆即可
3.点在园内且点不与大圆圆心重合,比较麻烦用到了相似什么的,我是看了一个大佬的做法链接附上链接在此
在这里插入图片描述
我们很容易就可以得到r1=sqrt((x1-x2)(x1-x2)+(y1-y2)(y1-y2));
然后通过相似三角形我们可以得到r1/((R+r1)/2)=(x2-x1)/(x2-x)=(y2-y1)/(y2-y);
最后稍微化简就可以直接得到(x,y).半径的话就只需要(r1+R)/2就行了。

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;

int main()
{
    double R,x1,x2,y1,y2;
    scanf("%lf%lf%lf%lf%lf",&R,&x1,&y1,&x2,&y2);
    double r1=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    if(r1>R)
    {
        printf("%.10f %.10f %.10f\n",x1,y1,R);
        return 0;
    }
    if(x1==x2 && y1==y2)
    {
        printf("%.10f %.10f %.10f\n",x1+0.5*R,y1,0.5*R);
        return 0;
    }
    double x=(R+r1)/(r1*2);
    printf("%.10f %.10f %.10f\n",x2-(x2-x1)*x,y2-(y2-y1)*x,(R+r1)/2);
    return 0;
}

H - 法法和古代字母

I - 法法和古代数学

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值