知识点:判断三角形是否为非退化三角形。
方法:判断三点是否在一条直线上,看斜率。但不能直接求斜率,会有精度损失而且还要分情况处理。解决如下:
bool ok(point a,point b,point c)
{
return (a.y-b.y)*(c.x-b.x)==(c.y-b.y)*(a.x-b.x);
}
如果ok函数放回true,表示三点共线,否则可以构成三角形
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <iostream>
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct point
{
ll x,y;
int id;
}a[N];
bool cmp(point a,point b)
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
bool ok(point a,point b,point c)
{
return (a.y-b.y)*(c.x-b.x)==(c.y-b.y)*(a.x-b.x);
}
int main()
{
int n;
// freopen("f.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<n;i++){
cin>>a[i].x>>a[i].y;
a[i].id=i+1;
}
sort(a,a+n,cmp);
int i;
for( i=2;i<n;i++){
if(a[i].x!=a[0].x)break;
}
for(int k=i;k<n;k++){
if(!ok(a[0],a[1],a[k])){
printf("%d %d %d\n",a[0].id,a[1].id,a[k].id);
break;
}
}
return 0;
}
知识点:
通分。
例如:
输入n,求 n(1/n+1/(n-1)+1/(n-2)+......+1/2+1/1),
方法:
化简一下,求分母是所有数的最小公倍数,然后求出分子之和,最后约分。
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
例题:
#include<iostream>
#include<sstream>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
int len(ll x)
{
stringstream ss;
ss<<x;
return ss.str().length();
}
void print(int n,char c)
{
while(n--)cout<<c;
}
void output(ll a,ll b,ll c)
{
if(b==0)cout<<a<<endl;
else{
int n=len(a);
print(n+1,' ');cout<<b<<endl;
cout<<a<<' ';print(len(c),'-');cout<<endl;
print(n+1,' ');cout<<c<<endl;
}
}
int main()
{
int n;
while(cin>>n&&n){
if(n==1){
output(1,0,0);continue;
}
ll x=1;
for(int i=2;i<n;i++)
x=lcm(x,i);
ll c=x,b=0;
for(int i=2;i<n;i++)
b+=x/i;
b*=n;
ll g=gcd(b,c);
b/=g;c/=g;
ll a=1+n+b/c;
b%=c;
output(a,b,c);
}
return 0;
}
知识点:欧拉函数
通式:
具体定义请看:百度百科
代码:求phi函数值
int phi(int n)
{
int m=sqrt(n+0.5);
int ans=n;
for(int i=2;i<=m;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0)n/=i;
}
}
if(n>1)ans=ans/n*(n-1);
return ans;
}
也可以先存到数组里,方法类似以筛法求素数,但本质上还是跟上述方法一样。
int phi[N];
void phi_table()
{
memset(phi,0,sizeof(phi));
phi[1]=1;
for(int i=2;i<N;i++)
if(!phi[i]){
for(int j=i;j<=N;j+=i){
if(!phi[j])phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
例题:
题意:求(0,0)-(n,n),范围内从原点可以看到的点的数量
分析:
对于点(x, y), 若g = gcd(x, y) > 1,则该点必被点(x/g, y/g)所挡住。
因此所见点除了(1, 0)和(0, 1)满足横纵坐标互素。
最终答案为,其中的+3对应(1, 1) (1, 0) (0, 1)三个点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1010;
int phi[N];
void phi_table()
{
memset(phi,0,sizeof(phi));
for(int i=2;i<N;i++)
if(!phi[i]){
for(int j=i;j<=N;j+=i){
if(!phi[j])phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
int main()
{
phi_table();
for(int i=2;i<=N;i++)phi[i]+=phi[i-1];
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
int n;
scanf("%d",&n);
printf("%d %d %d\n",cas,n,phi[n]*2+3);
}
return 0;
}
欧拉函数的题目还有很多,基础的有:
http://poj.org/problem?id=2407 直接求欧拉函数
http://poj.org/problem?id=2478 求欧拉函数的和
UVA 10214 这题是紫书上的一道题目,书上提供了欧拉函数的解法,还可以用莫比乌斯反演求。