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 }
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 }
顺便 提下 对于一个数中含有多少个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:
恐惧来源于自身 而于外界无关 来源于内心
just follow your heart