zoukankan      html  css  js  c++  java
  • UVa11327

    题目大意

    我们知道每一个有理数都可以表示为 (frac{p}{q}) 的形式,其中 (gcd(p,q)=1)。现在我们枚举所有 (<1) 的有理数,很显然我们可以用下面这段伪代码:

    for d = 1 to infinity do
        for n = 0 to d do
            if gcd(n,d) = 1 then print n / d
    

    根据这样的代码可以构造出一个包含所有 (<1) 的有理数序列。现在有一个数 (k),请你求出这个序列中第 (k) 个数。

    多组数据,每行一个正整数 (k),直到读入 (k=0) 为止。(kleq 12158598919)

    分析

    伪代码表示的意思就是这个序列排序方式的第一关键字是分母,第二关键字是分子。而由于分数小于 (1),所以分子显然比分母小。

    考虑以数 (t) 为分母的分数,那么这样的在序列中的数一共有 (sumlimits_{i=1}^n[gcd(i,n)=1]) 个。而这正好是欧拉函数 (varphi(n)) 的定义式。

    所以我们先筛出欧拉函数,记录欧拉函数的前缀和,然后看一看这个 (k) 在哪两个前缀和之间。这一过程可以用二分实现,也就是二分出了分母。接下来我们拿 (k) 减去我们二分出的分母 (q) 的欧拉函数,也就是 (x=k-varphi(q))。这表示:所求的数是以 (q) 为分母的第 (x) 个有理数,这一部分可以使用暴力遍历解决。那么这样的运算次数应该是 (2 imes 10^5 + log(2 imes 10^5)+ 2 imes 10^5 imes log(2 imes 10^5)),是一个可以接受的复杂度。这里将 (kleq 12158598919) 使用分母 (qleq2 imes 10^5) 代替了。也可以理解为值域。

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    #pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    #pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=1e6+5; int pri[MAXN],phi[MAXN],tot;
    bitset<MAXN>ispri; int Sphi[MAXN];
    inline void init(){
        ispri[1]=phi[1]=true;
        for(int i=2;i<=MAXN-5;i++){
            if(!ispri[i]) pri[++tot]=i,phi[i]=i-1;
            for(int j=1;j<=tot&&i*pri[j]<=MAXN-5;j++){
                ispri[i*pri[j]]=true;
                if(i%pri[j]) phi[i*pri[j]]=phi[i]*phi[pri[j]];
                else{phi[i*pri[j]]=phi[i]*pri[j];break;}
            }
        }
        for(int i=1;i<=MAXN-5;i++) Sphi[i]=Sphi[i-1]+phi[i];
    }
    inline int gcd(int x,int y){
    	return __gcd(x,y);
    }
    inline bool check(int w,int x){
    	if(Sphi[w]>=x) return true;
    	else return false;
    }
    signed main()
    {
    	int T=read(); init();
    	while(T){
    		int n=T;
    		if(n<3){printf("%lld/%lld
    ",n-1,1);T=read(); continue;}
    		else n-=2;
    		int l=2,r=MAXN-1,mid;
    		while(l<r){
    			mid=(l+r)/2;
    			if(Sphi[mid]<=n) l=mid+1;
    			else r=mid;
    		}
    		int lft=n-Sphi[r-1],i;
    		for(i=1;i<=r&&lft>=0;i++) if(gcd(i,r)==1) lft--;
    		write(i-1),putchar('/'),write(r),puts("");
    		T=read();
    	}
    }
    
  • 相关阅读:
    Annotation
    GIT的作用以及Versioncontrol为什么要用GIT
    Http协议
    人工智能的可怕与不可怕
    Makefile简易教程
    Node.js 学习笔记之一:学习规划 & 认知 Node.js
    《大教堂与集市》的启示 — 软件工程的另一种选择
    Git简易教程
    谈谈买书与读书
    clang编译器简介
  • 原文地址:https://www.cnblogs.com/AllWeKnow/p/14315526.html
Copyright © 2011-2022 走看看