小数问题
本文的主要內容是探討關于小數的一些問題,先介紹小數與分數的轉化,然后再來探討小數循環節等問題。其中涉及
到一些數論的內容,本文會進行詳細介紹。
題目:http://acm.hdu.edu.cn/showproblem.php?pid=1717
題意:給定一個純小數,將其轉化為分數輸出。
代碼:
#include <iostream> #include <string.h> #include <stdio.h>using namespace std; const int N = 15;int gcd(int a, int b) {return b ? gcd(b, a % b) : a; }void DecimalToFraction(char str[]) {int a = 0;int b = 0;int L1 = 0;int L2 = 0;int len = strlen(str);for(int i = 2; i < len; i++){if(str[i] == '(') break;a = a * 10 + str[i] - '0';L1++;}bool flag = 0;for(int i = 2; i < len; i++){if(str[i] == '(' || str[i] == ')'){flag = 1;continue;}b = b * 10 + str[i] - '0';L2++;}L2 -= L1;int p = b - a;int q = 0;if(!flag){p = b;q = 1;L2 = 0;}for(int i = 0; i < L2; i++)q = q * 10 + 9;for(int i = 0; i < L1; i++)q = q * 10;int g = gcd(p, q);p /= g;q /= g;printf("%d/%d\n", p, q); }int main() {int T;char str[N];scanf("%d", &T);while(T--){scanf("%s", str);DecimalToFraction(str);}return 0; }
題目:http://acm.hdu.edu.cn/showproblem.php?pid=2522
題意:給定一個分數,將其轉化為小數。本題需要用到如下定理
? ??
代碼:
#include <iostream> #include <string.h> #include <stdio.h>using namespace std; const int N = 100005;void FractionToDecimal(int n) {//負數標識bool isNeg = 0;if(n < 0){n = -n;isNeg = 1;}int res[N], ok[N];memset(res, 0, sizeof(res));memset(ok, 0, sizeof(ok));int k = 1;ok[k] = 1;int cnt = 0;while(k && n != 1){k *= 10;res[cnt++] = k / n;k %= n;if(ok[k]) break;ok[k] = 1;}if(isNeg) printf("-");if(n == 1) puts("1");else{printf("0.");for(int i = 0; i < cnt; i++)printf("%d", res[i]);puts("");} }int main() {int T, n;scanf("%d", &T);while(T--){scanf("%d", &n);FractionToDecimal(n);}return 0; }
題目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1037
題意:求小于等于的數中倒數循環節長度最長的那個數,其中。
分析:從上題的定理看,我們需要在小于等于的數中找一個數,使得同余方程的最小正
? ? ?整數解最大。很明顯,此方程的最大正整數解為,如果10為模的一個原根,那么將得到方程的最
? ? ?小正整數解為,這時得到的循環節當然也就最長。
? ? ?設小于等于且原根為10的最大的素數為。接下來,看似只需要枚舉閉區間內的每個數,找
? ? ?出滿足同余方程的最小正整數解為的所有數,然后取循環節長度最大的那個。
? ? ?但是遺憾的是,枚舉的數可能比較多,而且每次枚舉都需要解同余方程,時間花費很多。實際上只需要枚舉
? ? ?原根存在的。根據數論原根中的一個定理
? ? ? ?
? ? ?根據上題的定理知道,肯定不含有2,所以只需要枚舉形如的數即可。
? ? ?我們要在閉區間內找形如且原根為10的所有。如果原根為10,那么同余方程的最小正整數解
? ? ?為,也就是小數循環節的長度,在數論歐拉函數章節中,學過。
? ? ?綜上所述,本題思路為:從開始往下枚舉,直到為素數且10為模的一個原根時停止,判斷是
? ? ?否形如,如果是,進一步驗證是否是的最小正整數解,最終取循環節長度最大
? ? ?的。
代碼:
#include <iostream> #include <stdlib.h> #include <string.h> #include <algorithm> #include <assert.h> #include <stdio.h> #include <math.h> #include <vector>const int Times = 10; const int N = 1000005;using namespace std; typedef long long LL;bool prime[N]; int p[N]; int cnt;LL gcd(LL a, LL b) {return b? gcd(b, a % b) : a; }LL multi(LL a, LL b, LL m) {LL ans = 0;a %= m;while(b){if(b & 1){ans = (ans + a) % m;b--;}b >>= 1;a = (a + a) % m;}return ans; }LL quick_mod(LL a, LL b, LL m) {LL ans = 1;a %= m;while(b){if(b & 1){ans = multi(ans, a, m);b--;}b >>= 1;a = multi(a, a, m);}return ans; }bool Miller_Rabin(LL n) {if(n == 2) return true;if(n < 2 || !(n & 1)) return false;LL m = n - 1;int k = 0;while((m & 1) == 0){k++;m >>= 1;}for(int i = 0; i < Times; i++){LL a = rand() % (n - 1) + 1;LL x = quick_mod(a, m, n);LL y = 0;for(int j = 0; j < k; j++){y = multi(x, x, n);if(y == 1 && x != 1 && x != n - 1) return false;x = y;}if(y != 1) return false;}return true; }LL pollard_rho(LL n, LL c) {LL i = 1, k = 2;LL x = rand() % (n - 1) + 1;LL y = x;while(true){i++;x = (multi(x, x, n) + c) % n;LL d = gcd((y - x + n) % n, n);if(1 < d && d < n) return d;if(y == x) return n;if(i == k){y = x;k <<= 1;}} }void find(LL n, int c, vector<LL> &pri) {if(n == 1) return;if(Miller_Rabin(n)){pri.push_back(n);return ;}LL p = n;int k = c;while(p >= n) p = pollard_rho(p, c--);find(p, k, pri);find(n / p, k, pri); }void Divide(LL n, vector<LL> &pri, vector<int> &num) {find(n, 120, pri);sort(pri.begin(), pri.end());num.push_back(1);int k = 1;for(int i = 1; i < pri.size(); i++){if(pri[i] == pri[i - 1])++num[k - 1];else{num.push_back(1);pri[k++] = pri[i];}}pri.resize(num.size()); }void SearchFactor(int dept, LL ans, vector<LL> &pri, vector<int> &num, vector<LL> &fac) {if(dept == num.size()){fac.push_back(ans);return;}for(int i = 0; i <= num[dept]; i++){SearchFactor(dept + 1, ans, pri, num, fac);ans *= pri[dept];} }vector<LL> FindFactor(LL n) {int cnt;vector<LL> pri;vector<int> num;vector<LL> fac;Divide(n, pri, num);SearchFactor(0, 1, pri, num, fac);sort(fac.begin(), fac.end());return fac; }//素數篩選 void PrimeFilter() {cnt = 0;memset(prime, true, sizeof(prime));for(int i = 2; i < N; i++){if(prime[i]){p[cnt++] = i;for(int j = i + i; j < N; j += i)prime[j] = false;}} }bool Judge(LL m, LL &phi, bool &isprime) {// p^1if(Miller_Rabin(m)){phi = m - 1;isprime = true;return true;}//p^2LL srt = (LL)sqrt(1.0 * m);if(srt * srt == m && Miller_Rabin(srt)){phi = srt * (srt - 1);return true;}//p^3, p^4, ...LL tm = m;LL fm = 1;for(int i = 0; i < cnt; i++){if(tm % p[i] == 0){fm = p[i];while(tm % p[i] == 0){tm /= p[i];fm *= p[i];}if(tm == 1){phi = fm - fm / p[i];return true;}break;}}return false; }bool Success(LL m, LL &loop, bool &ok) {LL phi = 0;bool isprime = false;if(!Judge(m, phi, isprime))return false;LL res = 0;vector<LL> fac = FindFactor(phi);for(int i = 0; i < fac.size(); i++){if(quick_mod(10, fac[i], m) == 1){res = fac[i];break;}}if(res != phi)return false;loop = phi;if(isprime)ok = true;return true; }int main() {LL n;PrimeFilter();while(scanf("%I64d", &n) != EOF){n++;bool ok = 0;LL ans = 0;LL res = 0;while(n--){LL loop = 0;if(Success(n, loop, ok)){if(ans < loop){ans = loop;res = n;}if(ok){printf("%I64d\n", res);break;}}}}return 0; }
總結