原题摘录:循环小数(Repeating Decimals,ACM/ICPC World Finals 1990,UVa202)
输入整数a[0,3000]和b[1,3000],输出a/b的循环小数以及其循环节长度.例如a=5,b=43,小数表示为0.(116279069767441860465),循环节长度为21.
本题实际上是模拟长除法的计算过程,其中每一次除法时都有被除数和余数,当被除数出现重复就表示出现循环节了.所以要记录每一次的被除数及其在循环小数中的位置<是否已经想到键值对>,需要注意,当被除数不够除时,每一次补零也需要记录及其对应的位置.
1.在Map初始状态时所有值均为0.每当有一个被除数作为键存进去后,值就++(通过增加答案长度的同时达到此目的,一石二鸟),当下一个被除数进来时,如果相同,那么他就已经有对应的值.达到检查是否重复的目的.
2.小数位通过记录每次对应的新的余数*10/const被除数,然后转化为字符添加到ans中去.新的余数=旧的余数*10%const被除数
完整代码:
说明:string.insert(index,"string").在index位置插入字符串string
还有一个典型例子是:反片语(Ananagram,UVa 156)
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <assert.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
const int maxn=3000 + 10;
map<int,int> Pos;
void solve(int n,const int d,string& ans,int& r)
{
assert(n%d&&n<d);//不能整除且余数小于被除数
ans=".";
Pos.clear();
while(true){
n*=10;
int p=Pos[n];
if(p==0) Pos[n]=ans.size();
else{
r=ans.size()-p;
if(r>50) {ans.erase(p+50);ans+="...";}
ans.insert(p,"(");
ans+=")";
break;
}
if(n<d) {ans+='0';continue;}//补0
int div=n/d,mod=n%d;
ans+=(char)(div+'0');
n=mod;
if(n==0) {ans+="(0)";r=-1;break; }
}
}
int main(int argc, char** argv)
{
int a,b;
while(cin>>a>>b){
string ans="0.(0)";//赋值对答案无影响,标记出答案的样式,后面会进行修改
int r=1;
if(a%b)
solve(a%b,b,ans,r);//四个参数:余数,被除数,循环小数,循环节长度 例5/43=0.(116279069767441860465) 21
cout<<a<<"/"<<b<<"="<<a/b<<ans<<endl;
cout<<"repeating cycle number:"<<r<<endl;
cout<<endl;
}
return 0;
}
附:注意标题,是查重,不是去重(set)