SB树

1.farey 序列(法里序列)
POJ - 2478

题意:
F2 = {1/2} 
F3 = {1/3, 1/2, 2/3} 
F4 = {1/4, 1/3, 1/2, 2/3, 3/4} 
F5 = {1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5}
问Fn有多少项 

解法,可以看出来,Fn的解就是从2到n的欧拉函数的和
打个表求欧拉函数就行了,然后可以顺便把前缀和求出来,这样查询就是O(1)

(最近输入挂很迷啊,加了输入挂T???

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ld long double
#define ll long long
using namespace std;
#define ll long long
const int maxn = 1e6+10;
int phi[maxn];
/*inline void read(int &res)
{
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c==EOF) {res=0;return;}
        c=getchar();
    }
    res=c-'0';c=getchar();
    while(c>='0'&&c<='9')
        res=res*10+c-'0';
}*/
ll sum[maxn];
void phi_table(int n)
{
    for(int i=2;i<=n;i++) phi[i]=0;
    phi[1]=1;
    for(int i=2;i<=n;i++)
    if(!phi[i])
    {
        for(int j=i;j<=n;j+=i){
            if(phi[j]==0) phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
    }
    for(int i=2;i<=n;i++)
        sum[i]=sum[i-1]+phi[i];
}
int main()
{
    int n;
    phi_table(1000000);
    while(scanf("%d",n),n)
    {
        ll ans=0;
        printf("%I64d\n",sum[n]);
    }
    return 0;
}

2.Stern-Brocot Tree

假如序列中有三个连续元素x1/y1, x2/y2, x3/y3,则有x2 = x1+x3; y2 = y1+y3;
并且有x1*y2 – x2*y1 = 1。这条性质保证构造出来的分式肯定是不可约分式。

性质:
1.Stern-Brocot树可以构成所有有理数。
2.Stern-Brocot树构成的所有分数均为最简分数,即gcd(m,n)==1。
3.任意两个构造时相邻的两个分数都满足m1n2-m2n1==1。

所以我们可以根据SB数的性质,去二分构造分数

HDU 6209 The Intersection

题意:给k,求 k2/3 .

分析,这个卡精度呀,double会wa,可以用long double
根据SB树的构造,把小数化成分数

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ld long double
#define ll long long

using namespace std;

int fz,fm;
void solve(int z1,int m1,int z2,int m2,ld xs)
{
    if(z1==z2&&m1==m2) return ;
    if(m1>100000||m2>100000) return;
    if(abs((ld)fz/fm-xs)>abs((ld)z1/m1-xs)) fz=z1,fm=m1;
    if(abs((ld)fz/fm-xs)>abs((ld)z2/m2-xs)) fz=z2,fm=m2;
    int z=z1+z2,m=m1+m2;
    ld tt=(ld)z/m;
    if(tt<xs) solve(z,m,z2,m2,xs);
    else solve(z1,m1,z,m,xs);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll k;
        scanf("%lld",&k);
        int flag=0;
        for(ll i=1;i<=10000;i++)
        {
            if(i*i*i==k*k)
            {
                flag=1;
                printf("%lld/1\n",i);
                break;
            }
            if(i*i*i==k)
            {
                flag=1;
                printf("%lld/1\n",i*i);
                break;
            }
        }
        if(flag) continue;
        ld x=(ld)pow((ld)k,(ld)2.0/3.0);//这个pow里面两个都要加ld....
        int zs=(int)floor(x);
        ld xs=x-zs;
        fz=0,fm=1;
        solve(0,1,1,1,xs);
        printf("%d/%d\n",zs*fm+fz,fm);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值