hdu--2522--循环节

这题 还是靠caicai过的 因为他写过一篇 关于这个的博客 当时 没好好的去看它~~

主要 我一开始自己没做出来 因为有个很重要的定理不知道---当在小数部分出现相同余数 就证明出现循环节了

因为不知道这个 我就一直纠结怎么判断循环节...

然后就是模拟 除法 进行运算了 *10 /x   *10 & x

看下这篇文章 caicai推的 的确不错~    传送

一般 写的都是用hash记录余数 判断是否重复出现  这样会多开个数组  那里介绍的方法更好

贴下caicai的代码 还有我根据它修改后 适用于本题的 但他的更能适应于一般所有情况

 1 #include <iostream>
 2 #include <cmath>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 int lowbit( int n )
 7 {
 8     return n & -n;
 9 }
10 
11 int main()
12 {
13     cin.sync_with_stdio(false);
14     int n , x , val , num , num2 , num5 , left , mmax;
15     while( cin >> n )
16     {
17         while(n--)
18         {
19             num5 = 0;
20             cin >> x;
21             if(x<0)
22             {
23                 x = -x;
24                 cout << "-";
25             }
26             num = 1 % x;
27             val = x;
28             if( x==1 )
29             {
30                 cout << "1" << endl;
31                 continue;
32             }
33             else
34             {
35                 cout << "0.";
36             }
37             num2 = (int)log2( lowbit(x) );
38             while( val%5 == 0 )
39             {
40                 num5++;
41                 val /= 5;
42             }
43             mmax = max( num2 , num5 );
44             while( mmax-- )
45             {
46                 cout << num * 10 /  x;
47                 num = num * 10 % x;
48             }
49             left = num;
50             while( num )
51             {
52                 cout << num * 10 / x;
53                 num = num * 10 % x;
54                 if( num == left )
55                 {
56                     break;
57                 }
58             }
59             cout << endl;
60         }
61     }
62     return 0;
63 }
View Code

 

 1 #include<iostream>
 2 #include<map>
 3 #include<cmath>
 4 using namespace std;
 5 
 6 int gcd(int x, int y)
 7 {
 8     return y == 0 ? x : gcd(y, x % y);
 9 }
10 
11 int main()
12 {
13     int x, y, tmp;
14     while(~scanf("%d%d", &x, &y))
15     {
16         int div = gcd(x, y);
17         x /= div;  // 例如4/24要转化成1/6,不然的话会对后面分母计算2与5的因子数有干扰
18         y /= div;
19         int num = x % y;
20         printf("%d.", x / y); // 首先输出整数部分
21         if(x % y == 0) // 若是4/2则没必要计算,直接输出结果
22         {
23             printf("0\n");
24             continue;
25         }
26         int aa, bb = 0, tmp = y;
27         aa = (int)log2((tmp & (-tmp)));  // 计算分母中质因数2的个数,这里用了个小技巧
28         while(tmp % 5 == 0)  // 计算分母中质因数5的个数
29         {
30             bb++;
31             tmp /= 5;
32         }
33         aa = aa > bb ? aa : bb;  // 质因数2和5的数量谁多,循环节就从几位开始,例如45/56,aa=3
34         while(aa--)  // 前几位小数不算在循环节内,直接输出
35         {
36             printf("%d", int(num * 10 / y));
37             num = num * 10 % y;
38         }
39         bb = num; // 循环节开始时的余数,第二个循环节头,即循环结束位置,应与此余数相同
40         if(num)  // 需要判断当前余数是否为零,否则某些输出的末尾会带有(0)导致输出格式问题
41         {
42             printf("(");
43             printf("%d", int(num * 10 / y));
44             num = num * 10 % y; // 这两句不可少,若为1/3,则结果为没有前置小数的一位循环节0.(3),需特殊处理
45             while(num != bb)
46             {
47                 printf("%d", int(num * 10 / y));
48                 num = num * 10 % y;
49             }
50             printf(")");
51         }
52         printf("\n");
53     }
54     return 0;
55 }
View Code

顺便 提下 对于一个数中含有多少个2的计算  x & -x 可以这样理解

假如X=24 11000  因为我们可以计算得到从右往左数 第一个 1 的位置及它代表的值 这边就是8了嘛

我们可以这样看 24 = 8 * ( 1 + 2 ) 这样你就能发现 因为第一个8提供了括号中的一个1 导致后面的数肯定是奇数 那么这个数它所有的2的个数 就肯定由第一个 1 出现的位置的值来决定了

至于 奇数 就更简单了 因为 由二进制表示的数如果原来是奇数 那么它的第一位 肯定是1  2^0*1 = 1这样 就2的个数是0了 通过log2(x&-x)来计算

这个x & -x其实就是lowbit(x)在 树状数组的时候 我们也用到了

---尽扯了些没用的 =-=

 

today:

  恐惧来源于自身 而于外界无关 来源于内心

 

posted @ 2014-07-27 15:58  radical  阅读(192)  评论(0编辑  收藏  举报