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;
}
假如序列中有三个连续元素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);
}
}