zoukankan      html  css  js  c++  java
  • HDU 2522 & AOJ 441 & AOJ 364 关于小数和分数的转换

    总结一下小数和分数之间精确转换的方法。

    首先是分数转换为小数,这个比较简单,先看题 http://acm.hdu.edu.cn/showproblem.php?pid=2522

    输入一个n,求1/n的精确表示,如果有循环节只输出最小的一个。

    手动模拟一下出发,会发现每次都是上一次除法剩下来的余数*10然后继续下一次计算,什么时候会出现循环呢,显然是余数出现重复的时候。

    余数判断重复可以搞一个hash或者set,这里n不是特别大,直接用数组就可以了。

    另外写的时候注意一下处理整除的情况。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 1e5 + 10;
    bool vis[maxn];
    
    int main() {
    	int n, T; scanf("%d", &T);
    	while (T--) {
    		scanf("%d", &n);
    		memset(vis, false, sizeof(vis));
    		int num = abs(n), nowmod = 1, nowval;
    		vis[1] = true; vis[0] = true;
    		if (num == 1) {
    			puts("1"); continue;
    		}
    		if (n < 0) putchar('-');
    		printf("0.");
    		while (1) {
    			nowval = (nowmod * 10) / num;
    			nowmod = (nowmod * 10) % num;
    			printf("%d", nowval);
    			if (vis[nowmod]) break;
    			vis[nowmod] = true;
    		}
    		putchar('
    ');
    	}
    	return 0;
    }

    另外看一下 http://icpc.ahu.edu.cn/OJ/Problem.aspx?id=441

    输入两个数A,B(0<A<=B<=1000),精确输出A/B,并且输出最小循环节长度。

    处理方法和上面那个一样,使劲除就好了。 长度的处理就是把原来的vis数组给换成是记录上一次这个数出现的位置即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1000 + 10;
    int pre_pos[maxn];
    
    int main() {
    	int A, B;
    	while (scanf("%d%d", &A, &B), A) {
    		memset(pre_pos, -1, sizeof(pre_pos));
    		A %= B;
    		if (A == 0) {
    			puts(".
    This expansion terminates.");
    			continue;
    		}
    		int nowmod = A, nowval, len, nowpos = 0;
    		pre_pos[A] = 0;
    		bool terminal = false;
    		putchar('.');
    		while (1) {
    			nowpos++;
    			nowval = (nowmod * 10) / B;
    			nowmod = (nowmod * 10) % B;
    			if (nowval == 0 && nowmod == 0) {
    				terminal = true; break;
    			}
    			printf("%d", nowval);
    			if (pre_pos[nowmod] != -1) {
    				len = nowpos - pre_pos[nowmod];
    				break;
    			}
    			pre_pos[nowmod] = nowpos;
    		}
    		putchar('
    ');
    		if (terminal) puts("This expansion terminates.");
    		else printf("The last %d digits repeat forever.
    ", len);
     	}
    	return 0;
    }
    

     

    然后是给你小数,指定循环节,让你求分数。 http://icpc.ahu.edu.cn/OJ/Problem.aspx?id=364

    这类问题比上面那种要麻烦,需要推一下公式。

    给你一个小数 N = 0.A(B),括号内的为循环节,假设A的长度为LenA,B的长度为LenB,有

    N * 10^LenA = A.(B)  ----> N * 10^LenA - A = 0.(B)

    设Y = 0.(B) 有

    Y * 10^LenB = B.(B) 

    Y * 10^LenB - B = 0.(B) = Y

    Y = B / (10^LenB - 1) = N * 10^LenA - A

    N = (B + A * (10^LenB - 1)) / ( 10^LenA * (10^LenB - 1))

    分别计算出分子和分母的值,然后求一下gcd,约分一下就好了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
     
    using namespace std;
     
    typedef long long LL;
     
    LL gcd(LL a,LL b) {
        return b == 0 ? a : gcd(b,a % b);
    }
     
    LL pow10(LL a) {
        LL ret = 1;
        while(a--) ret *= 10;
        return ret;
    }
     
    void display(int a,int b) {
        int n = 0,m = 0,ta = a,tb = b;
     
        while(ta) {
            n++; ta /= 10;
        }
     
        while(tb) {
            m++; tb /= 10;
        }
     
        LL denominator,numerator,div;
        denominator = pow10(n) * (pow10(m) - 1);
        numerator = a * (pow10(m) - 1) + b;
        div = gcd(denominator,numerator);
         
        cout << numerator / div << "/" << denominator / div << endl;
    }
     
    int main() {
        int T; cin >>T;
        while(T--) {
            int a,b; cin >> a >> b;
            display(a,b);
        }
        return 0;
    }
    

      

  • 相关阅读:
    AtCoder agc023_f
    CodeForces 1328
    洛谷 P4437
    Spark读取txt文件跳过第一行
    斯特林数学习笔记。
    hackrank subsets
    题解 CF1004F 【Sonya and Bitwise OR】
    [NOI2020]美食家
    Educational Codeforces Round 94 题解
    Delphi 与 C/C++ 数据类型对照表
  • 原文地址:https://www.cnblogs.com/rolight/p/3941931.html
Copyright © 2011-2022 走看看