ACM 数论 SGU 444 Headstrong Student

http://acm.sgu.ru/problem.php?contest=0&problem=444

444. Headstrong Student
Time limit per test: 0.75 second(s) 
Memory limit: 262144 kilobytes
input: standard 
output: standard

You are a teacher at a cram school for elementary school pupils. One day, you showed your students how to calculate division of fraction in a class of mathematics. Your lesson was kind and fluent, and it seemed everything was going so well — except for one thing. After some experiences, a student Max got so curious about how precise he could compute the quotient. He tried many divisions asking you for a help, and finally found a case where the answer became an infinite fraction. He was fascinated with such a case, so he continued computing the answer. But it was clear for you the answer was an infinite fraction — no matter how many digits he computed, he wouldn't reach the end. Since you have many other things to tell in today's class, you can't leave this as it is. So you decided to use a computer to calculate the answer in turn of him. Actually you succeeded to persuade him that he was going into a loop, so it was enough for him to know how long he could compute before entering a loop. Your task now is to write a program which computes where the recurring part starts and the length of the recurring part, for given dividend/divisor pairs. All computation should be done in decimal numbers. If the specified dividend/divisor pair gives a finite fraction, your program should treat the length of the recurring part as 0. 
Input
The input consists of a line containing two positive integers  x  and  y , which specifies the dividend and the divisor, respectively. You may assume that 1 ≤  x y  ≤ 1000000. 
Output
Your program should output a line containing two integers separated by exactly one blank character. The former describes the number of digits after the decimal point before the recurring part starts. And the latter describes the length of the recurring part. 
Example(s)
sample input
sample output
1 3
0 1

sample input
sample output
1 6
1 1

sample input
sample output
5 3
0 1

sample input
sample output
5 4
2 0

sample input
sample output
200 2
0 0

sample input
sample output
25000 99
0 2


大意:求小数的循环节——开始的位置,循环的长度

三种方法,依次为:

1.暴力循环匹配 O(m^2) m==1E6

2.求余数相等 O(n)

3.用循环小数的定理 O(n)

/*
 * Author: NICK WONG
 * Created Time:  7/26/2014 12:54:28
 * File Name: a.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long LL;
const int maxn=11000000;
const int maxlen=100000;
const long long maxint=-1u>>1;
const long long maxlong=maxint*maxint;
int x,y;
int a[maxn];

void work()
{
    x%=y;   
    if (x%y==0)
    {
        cout  << 0 << " " << 0 << endl;
        return;
    }
    for (int i=0; i<=maxn-10; i++)
    {
        x*=10;
        a[i]=x/y;
        x%=y;
        if (x==0)
        {
            cout  << i+1 << " " << 0 << endl;
            return;
        }
        //cout << a[i];
        //cout << x << " " << a[i] << endl;
    }
     
    /*cout << endl;
    for (int i=0; i<=50; i++) cout << a[i];
    cout << endl;
    cout << endl;
    for (int i=0; i<=50; i++) cout << a[30402+i];
    cout << endl;
    */
    for (int i=0; i<=10; i++)
    {
        for (int len=1; len<=maxlen*10; len++)
        {
            bool flag=true;
            int j=i+len-1;
            for (int k=1; k<=10; k++)
                if (!flag) break; else
                for (int l=i; l<=j; l++)
                    if (a[l]!=a[l+len*k]) 
                    {
                        flag=false;
                        break;
                    }
            if (flag)
            {
                cout << i << " " << len << endl;
                return;
            }
        }
    }
    cout << "big" << endl;
    //while (1) ;
}

int main()
{
    while (cin >> x >> y)
    {
        work();
    }
    return 0;
}

#include<iostream>
#include<cstring>
using namespace std;
const int maxn=11000000;
int x,y,i,f[maxn];

int main()
{
    cin >> x >> y;
    memset(f,-1,sizeof(f));
    x%=y;
    if (x%y==0)
    {
        cout  <<  "0 0" << endl;
        return 0;
    }
    f[x]=0;
    for (i=1; i<=maxn-1; i++)
    {
        x=x*10%y;
        if (f[x]!=-1) break; else f[x]=i;
        if (x==0)
        {
            cout  << i << " 0" << endl;
            return 0;
        }
    }
    cout << f[x] << " " << i-f[x] << endl;
    return 0;
}


/*
 * Author: NICK WONG
 * Created Time:  7/26/2014 20:18:46
 * File Name: B.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long LL;
const int maxn=10100;
const long long maxint=-1u>>1;
const long long maxlong=maxint*maxint;
int x,y,cn2,cn5;

int gcd(int a, int b)
{
    if (b==0) return a; 
    return gcd(b,a%b);
}

void work()
{
    int tmp=gcd(x,y);
    x/=tmp;
    y/=tmp;   
    x%=y;
    //cout << "1";
    cn2=cn5=0;
    while (y%2==0)
    {
        y/=2;
        cn2++;
    }
    
    while (y%5==0)
    {
        y/=5;
        cn5++;
    }
    cn2=max(cn2,cn5);
    if (y==1)
    {
        cout << cn2 << " " << 0 << endl;
        return;
    }
    //cout << "1";
    int sum=1;
    tmp=10;
    while (tmp%y!=1)
    {
        tmp=(tmp*10)%y;
        sum++;
    }
    cout << cn2 << " " << sum << endl;
}

int main()
{
    while (cin >> x >> y)
    {
        work();
    }
    return 0;
}

方法三预备知识:

sources:http://blog.csdn.net/niushuai666/article/details/6691041

http://wenku.baidu.com/view/53a96582d4d8d15abe234eab.html

1.1.2循环小数
1.1.2.1基本概念及定理  
循环小数:一个数的小数部分,如果从某一位起,一个或几个数字依次不断地重复出现,这样的数就叫做循环小数。循环小数是无限小数,它的位数是无限的。循环小数的小数部分中,依次不断重复的数字,叫做它的一个循环节。如果循环节从小数部分第一位(十分位)开始的,叫做纯循环小数;循环节不是从小数部分第一位开始的,叫做混循环小数。
定理一:如果最简分数的分母除2、5质因数外,不含其它质因数,这个分数能化成有限小数。将能化成有限小数的最简分数的分母进行质因数分解,看质因数2和5的幂指数,较大的那个指数的大小就是有限小数的位数。
定理二:如果最简分数的分母除2、5质因数外,含其它质因数,这个分数不能化成有限小数。
定理三:如果一个最简分数的分母里,如果只含有2,5以外的质因数,那么这个分数一定能化成纯循环小数,这个纯循环小数循环节的最少位数,等于9、99、999、9999 ……诸数中能被分母整除的最小那个数里9的个数 。
定理四:一个最简分数的分母里,如果除含有2或5质因数外,还含有其它质因数,那么这个分数一定能化成混循环小数。这个不纯循环部分里的数字的个数,等于2、5中较多的一个数的个数。循环节的最少位数等于9、99、999、9999 ……诸数中能被分母2、5以外的质因数(或质因数的乘积)整除的最小那个数里9的个数。
1.1.2.2循环小数化分数
1.1.2.2.1纯循环小数化分数
从小数点后面第一位就循环的小数叫做纯循环小数。
纯循环小数的小数部分可以化成分数,这个分数的分子是一个循环节表示的数,分母各位上的数都是9。9的个数与循环节的位数相同。能约分的要约分。
1.1.2.2.2混循环小数化分数
不是从小数点后第一位就循环的小数叫混循环小数。
一个混循环小数的小数部分可以化成分数,这个分数的分子是不循环部分和一个循环节的数字组成的数减去不循环部分的数字组成的数所得的差,分母就是按一个循环节的位数写几个9,再在后面按不循环部分的位数添写几个0组成的数.
详细内容:http://wenku.baidu.com/view/53a96582d4d8d15abe234eab.html




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值