hihocoder 编程练习赛77

题目1 : 右转九十度

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

假设一个机器人在笛卡尔坐标系上。它从(X1, Y1)移动到了(X2, Y2),然后向右转90度,继续前进。  

请你计算这个机器人继续前进过程中最先经过的整点是哪一个?

输入

四个整数X1, Y1, X2, Y2。

-1000000 ≤ X1, Y1, X2, Y2 ≤ 1000000 保证(X1, Y1)和(X2, Y2)是不同的点。

输出

两个整数X和Y代表最先经过的整点坐标。

样例输入

0 0 1 2

样例输出

3 1

 

题目分析:

1.题是什么?

    两个坐标,由坐标1运动到坐标2,然后右转90度继续运动,输出经过的第一个x与y皆为整数的点;

2.思路

    数学题自然数学解法求解

    我们设由(x_{1},y_{1})(x_{2},y_{2})经过的第一个点为(x_{2}+\Delta x,y_{2}+\Delta y),令dy=y_{2}-y_{1},dx=x_{2}-x_{1}.下面作图如下

现推理: 因为\angle 1+\angle 2=90^{o},\angle 2+\angle 3=90^{o},

              所以\angle 1=\angle 3,所以\tan \angle 1=\tan \angle 3

             所以\frac{\left |\Delta y \right |}{\left |\Delta x \right |}=\frac{\left |dy \right |}{\left |dx \right |}

 我们要找第一个点,也就是最小的一组 \left |\Delta y \right | 和 \left |\Delta x \right | , \left |dy \right |\left |dx \right |分别除以他们的最大公约数时自然就最小

             不知道怎么快速求两数字最大公约数的可以戳这儿(关于最大公约数求解算法的博客)

ac代码

#include <stdio.h>
#include <math.h>

int gcd(int a,int b){
	if(0==b) return a;
	return gcd(b,a%b);
}

void solve(){
	int x1,y1,x2,y2;
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	int dy=y2-y1,dx=x1-x2,gcdxy=gcd(fabs(dx),fabs(dy));
	printf("%d %d\n",x2+dy/gcdxy,y2+dx/gcdxy);
}

int main(){
	solve();
	return 0;
}

题目2 : 钝角三角形

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

一个圆周上均匀分布着N个点,按顺时针编号依次是1, 2, 3, ... N。  

现在其中K个点是特殊点,编号分别是A1, A2, ... AK。  

小Hi想知道以特殊点为顶点,能构成多少个不同的钝角三角形。

输入

第一行包含2个整数N,K。  

第二行包含K个整数,A1, A2, ... AK。  

对于50%的数据,1 ≤ K ≤ MIN(1000, N)  

对于100%的数据,1 ≤ K ≤ MIN(100000, N), 1 ≤ N ≤ 1000000000, 1 ≤ Ai ≤ N

输出

一个整数代表答案

样例输入

8 4  
1 3 4 7

样例输出

1

 

题目分析:

1.题是什么?

     圆周上面有k个点,这k个都属于n个均匀分布于圆周的点,,现在问你我从这k个点中选3个连成一个三角形,是钝角三角形的可能数为多少?

2.思路

    问题的核心在于钝角三角形的判定.

    首先得了解一个初中定理,圆的直径对应的角为直角,也就是说如果我们对于题给的案例做分析:

    如图,n=8,所以8个均分点,红色的代表是题目给的k个,如图1,3,4,7是红色,此时图中AD就是直径,因为是均分,这个自己看图理解一下,

    此时以ADB做三角形自然就是直接三角形(当然,D并不是k个中的一个,先理解),角ABD为直角.

    那什么时候为钝角呢?自然是当所选的点比D更靠近B时,都是钝角,比如点C,因为在直角的基础上加上了角DBC.

    序号i为对面的点的序号是多少? 当然是(i+n/2)%n

    根据上面这通分析,我们其实就是要在这一堆原本表示序号的数字中找到对于每个点i,i和它对面的点之间的可用k点数目对2的组合数,这个答案就是以i点做钝角三角形,钝角偏右的可能总数.

ac代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=100005;
int a[maxn];
ll cn2[maxn];

void initcn2(){
	for(ll i=2;i<maxn;i++) cn2[i]=i*(i-1)/2;
}

int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=0;i<k;i++) scanf("%d",&a[i]);
	initcn2();
	sort(a,a+k);
	ll ans=0;
	int i=0;
	while(a[i]<=n/2+1&&i<k){
		ans+=cn2[(lower_bound(a,a+k,a[i]+n/2)-(a+i))-1];
		i++;
	}
	while(i<k){
		ans+=cn2[(lower_bound(a,a+k,(a[i]+n/2)%n)-a)+k-i-1];
		i++;
	}
	printf("%lld\n",ans);
	
	return 0;
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值