先做2895题再做这题,会容易很多
这是一道模拟题。模拟题的第一要义就是把我们手动做这件事的逻辑理顺并以代码的形式表述出来。所以我第一步思考的是:「我是如何计算小数的?」「我是如何确定循环节的?」显然,我会观察每一次除的时候,这个被除数(即上一步的余数乘以 10)是否已经出现过。如果已经出现过,说明有循环节。
这说明需要一个记簿。我们使用 unordered_map<Dividend, BitPos>
,以被除数为键(因为我们查询的对象就是它),它出现的位数为值。因为这些记录不需要有序,所以使用哈希表而不是红黑树。
#include <cstdint>
#include <iostream>
#include <unordered_map>
int main() {
using u32 = uint32_t;
u32 t;
std::cin >> t;
for (u32 i = 0; i != t; ++i) {
u32 n, m;
std::cin >> n >> m;
std::cout << "case #" << i << ":\n" << n / m;
n = n % m * 10;
if (!n) {
std::cout << '\n';
continue;
}
std::cout << '.';
using BitPos = u32;
using Dividend = u32;
u32 bit_cnt = 1;
std::unordered_map<Dividend, BitPos> table{{n, bit_cnt}};
do {
std::cout << n / m;
n = n % m * 10;
if (auto [it, ok] = table.insert({n, bit_cnt += 1}); !ok) {
std::cout << '\n' << it->second << '-' << bit_cnt - 1;
break;
}
} while (n);
std::cout << '\n';
}
}
被一个逻辑搞了好久……余数一样对应的商可能不一样,如果不一样要往后挪一个才是循环开始的位置
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int T;
cin >> T;
for (int cse = 0; cse < T; cse++)
{
cout << "case #" << cse << ":" << endl;
int a, b;
cin >> a >> b;
vector<int> R; // 余数
vector<int> Q; // 商
int z = a / b; // 整数部分
cout << z << ".";
a %= b;
bool inf = false;
int begini,endi; //循环节开始和结束位
for(;;)
{
a *= 10;
int q = a / b;
int r = a % b;
a = r;
if (r == 0)
{
Q.push_back(q);
inf = false;
break;
}
else
{
vector<int>::iterator it = find(R.begin(), R.end(), r);
if (it == R.end()) // 余数不重复
{
Q.push_back(q);
R.push_back(r);
}
else // 余数重复
{
begini = it - R.begin(); // 这里是算的索引值,后面输出要 +1
inf = true;
if (q != Q[begini]) // 起初就是因为少了这个判断和 +1 的逻辑,试了很多次,样例都过不了
{
begini++;
Q.push_back(q); // 前面不相等的商不是循环节,因此要把这个商放进去
}
endi = Q.size();
break;
}
}
}
for (int i = 0; i < Q.size(); i++)
{
cout << Q[i];
}
cout << endl;
if (inf)
{
cout << (begini + 1) << '-' << endi << endl;
}
}
return 0;
}
不是很明白,这题为什么写的我自己都觉得乱
using namespace std;
int T,up,down;
int occurred[1000];
int main()
{
cin>>T;
for(int step=0;step>up>>down;
memset(occurred,0,sizeof(occurred));
int yu=up%down;
printf(“case #%d:\n0.”,step);
int pos=1;
while(yu!=0 && !occurred[yu])
{
occurred[yu]=pos++;
cout<<(yu10)/down;
yu=(yu10)%down;
}
if(yu==0) cout<<endl;
else
{
cout<<endl<<occurred[yu]<<’-‘<<pos-1<<endl;
}
}
return 0;
}
重要的一点是,只要记录这个余数有没有出现过即可,余数一样,后面的一切都会重复
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n,m;
cin>>n>>m;
int ans[10000],rmdr[10000];
int k=0,j=0,flag=0;
int intpart=n/m;
rmdr[j++]=n%m;
n%=m;
cout<<intpart<<'.';
while(n%m!=0)
{
n*=10;
ans[k]=n/m;
rmdr[j++]=n%m;
n%=m;
cout<<ans[k++];
for(int i=0;i<j-1;i++)
{
if(rmdr[i]==rmdr[j-1])
{
flag=1;
if(i==j-2)
{
cout<<endl<<i+1<<'-'<<i+1<<endl;
break;
}
else
{
cout<<endl<<i+1<<'-'<<j-1<<endl;
break;
}
}
}
if(flag==1)
break;
}
if(flag==0)
cout<<endl;
}
int main()
{
int T;
cin>>T;
for(int i=0;i<T;i++)
{
printf("case #%d:\n",i);
solve();
}
return 0;
}
很抱歉写的太杂乱了,但是具体思路是很简单的,存余数遍历即可
垃圾无限小数题毁我一生。
垃圾代码大家就别看了,只是试试能不能打全
…
using namespace std;
void solve()
{
int n,m;
cin>>n>>m;
int s[10000];
int t;
int i=0;
while(n!=0)
{
n=n10;
s[i]=n/m,n=n%m;
int flu=0;
for(t=0;t<=i;t++)
{
if(s[t]==s[i]&&t!=i)
{
int k=i-t;
int t1=t;
int n1=n;
int i1=i+1;
int flag=0;
t1+=1;
while(k–)
{
n1=n110;
s[i1]=n1/m,n1=n1%m;
if(s[i1]!=s[t1]) {flag=1;break;}
else t1++,i1++;
}
if(flag==1) break;
else {
k-=1;
if(k==1) i=t;
else i-=1;
flu=1;
}
}
if(flu==1) break;
}
i++;
if(flu==1) break;
}
t+=1;
cout<<”0.”;
for(int t=0;t<i;t++) cout<<s[t];
cout<<endl;
if(t<=i) cout<<t<<”-“<<i<>n;
for(int i=0;i<n;i++)
{
printf(“case #%d:\n”,i);
solve();
}
}
…
高精度+正则暴力求解,计算效率低下,仅供娱乐
import re
from decimal import *
getcontext().prec = 2077
for _ in range(int(input())):
print(f'case #{_}:')
a, b = map(Decimal, input().split())
s = str(a / b)
m = re.search(r'(.+?)(?=\1{10,})', s)
if m:
print(s[:m.end()])
print(f'{m.start() - 1}-{m.end() - 2}')
else:
print(s)
包代码时三个点的中英文模式没切换对(大雾