一、数三角形
什么叫三角形?这个应该是每个人都知道的。在本题中,我们不允许三角形出现退化的情况,即每条边的长度与每个角的大小也应大于0。
现在平面上有n个两两不重合的点,第i个点的坐标为(x[i],y[i])。你需要计算,以它们作为顶点,一共能构成的三角形的个数。注意,即使是两个全等的三角形,只要它们的位置是不同的,就认为是不同的三角形,详见样例。
暴力:看了一下n只有100,直接枚举3个顶点,用叉积或三角形三边关系(a+b>c(a<=b<=c))进行判断,n^3
给力点:可选取一个点为原点,进行极角排序,然后用同一角度的点与其他角度的用乘法原理匹配方案,为了避免180°三点共线如图:
可先将三、四象限的点旋转180°,再进行排序。
排序可用点x、y相对于z叉积大于0时,点x在y的逆时针方向,但这样会死循环(没确立起始点,角度大于180°时叉积为负,会分不清前后),由于作了以上旋转操作,没有大于180°的角,有不循环的前后之分,故不会出错。附代码:
#include |
02 |
#include |
03 |
#include |
04 |
#include |
05 |
#include |
06 |
#include |
07 |
#include |
08 |
#include |
09 |
#include |
10 |
#include |
11 |
#include |
12 |
#include |
13 |
#include |
14 |
using namespace std; |
15 |
int n,i,j,k,ans,tot; |
16 |
double x[110],y[110],s; |
17 |
int main() |
18 |
{ |
19 |
cin>>n; |
20 |
for(i=1;i<=n;i++) |
21 |
{ |
22 |
cin>>x[i]>>y[i]; |
23 |
} |
24 |
for(i=1;i<=n;i++) |
25 |
for(j=i+1;j<=n;j++) |
26 |
for(k=j+1;k<=n;k++) |
27 |
{ |
28 |
/*double xx=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); |
29 |
double yy=sqrt((x[i]-x[k])*(x[i]-x[k])+(y[i]-y[k])*(y[i]-y[k])); |
30 |
double zz=sqrt((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])); |
31 |
if (xx+yy>zz&&xx+zz>yy&&yy+zz>xx) |
32 |
{ |
33 |
if (not(x[i]==x[j]&&x[j]==x[k])&¬(y[i]==y[j]&&y[j]==y[k])) |
34 |
{*/ |
35 |
if ((x[i]-x[j])*(y[j]-y[k])!=(x[j]-x[k])*(y[i]-y[j]))ans++; |
36 |
/*} |
37 |
}*/ |
38 |
} |
39 |
cout< |
40 |
} |
|
|
二、4和7
萌萌哒doge突然想吃药了!
现在有一排格子,从左向右标号为0到m。doge最初在0号格子中。
一共有n堆药,第i堆药有a[i]粒,被放在b[i]格子里。
每次,萌萌哒doge可以跳到它右边4格或右边7格的位置。求它最多能吃到的药的个数。注意,doge不必跳到格子m,而是可以随时结束游戏。
做题时不知为何想不到,其实枚举一下就可发现规律:(任何题目,先打暴力,不仅可以对拍,还可以找规律,王道……)
可以调到的距离有:4、7、8、11、12、15、16、18、19、20……
可以发现,在距离大于17时都可以用4和7匹配到,此时我们是在第i个位置,用前i-1个位置的方案求解,取max时,只需将距离小于17的位置取max,大于17的,我们可以先存储一个数组s[i]表示,1~i+1的方案中的最大值,o(1)求出,取max,避免一个个枚举o(n)会超时,然后由于题目说可以随时结束游戏,那么就要用ans在更新时随时记录方案的最大值,最后输出。
三、反射镜
注:坐标平面没有边缘,光线不会因为碰到边界而中途停下,m的意义是所有镜子坐标绝对值的最大值不会超过m。
从前有一个坐标网格(其中坐标的绝对值不会超过m)。从左到右x坐标逐渐增加,而从下到上y坐标逐渐增加。
在网格中摆放着n面镜子,第i面镜子的坐标为(x[i],y[i])。镜子均与坐标轴成45°角。所以共有两种类型的镜子:“\”型和“/”型。特殊地,原点处不会有任何镜子,也不会有某个位置有多面镜子。
镜子的两个面都能够反射光线,而中间不透光,例如,对于一个“/”型镜子,从下面射入的光线会被反射到右方向,而从左面射入的光线会被反射到上方向。
现有一条光线从原点所在格子沿x轴正方向射出,求它走过$T$格路程后所在的位置。
由数据范围入手,假设我们用普通的模拟(即一面镜子一面镜子的走下去,直到走完路程为止),那么在不出现循环的情况下,要走n次,n<=100000,故可以做。而当出现循环时,易证得循环只可能从起点时出现,如图:
这时就是最后15分的差别了,最后数据将路程调至最大,然后以较小距离摆放镜子,循环走下去——超时,这时我们可以记录一下走到每个镜子面(即要分方向)的时间点,然后用当前时间点与其求差,得出循环的时间,求mod,就省去多次循环模拟的时间。
接着就得解决寻找当前镜子的后继,可以分别按横坐标、纵坐标排序,二分得出,当然,我们试验发现,每次二分找到的都是当前镜子在数组中的位置+1或-1,那么我们可以记下每面镜子在排序后两个数组中的位置,O(1)得出,起点除外,要二分,或者把它也加进去排序,再记下在数组中的位置。
依上所述,时间复杂度为nlogn+logn或o(n)+logn