幾道數學問題 (未完成)

知識點:判斷三角形是否爲非退化三角形。

方法:判斷三點是否在一條直線上,看斜率。但不能直接求斜率,會有精度損失而且還要分情況處理。解決如下:

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,表示三點共線,否則可以構成三角形

例題:Codeforces 618C

#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;}

例題:

UVa 10288

#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);
        }
    }
}
例題:

poj 3090

http://poj.org/images/3090_1.png

題意:求(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  這題是紫書上的一道題目,書上提供了歐拉函數的解法,還可以用莫比烏斯反演求。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章