【USACO2.4.5】分数化小数 模拟

模拟手算除法= = 


循环节判断才是这题恶心的地方啦。





加入这里出现了425的情况。 (这题只有整数部分,小数部分都是0, 所以DE应该也是0)






第二次,又在这里出现了425. 说明循环出现了~


为啥? 因为425肯定后面又是补0来计算…… 所以肯定就重复了。


这里判断重复的地方可以用map来判断,这题的小数位数最多高达6万位……其实不需要map判断的,直接O(1)的判断也可以的啦, 因为被除数只有100000,用个bool数组判断一下,看是否被使用过就可以啦。 

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.003 secs, 4284 KB]
   Test 2: TEST OK [0.003 secs, 4284 KB]
   Test 3: TEST OK [0.003 secs, 4284 KB]
   Test 4: TEST OK [0.003 secs, 4284 KB]
   Test 5: TEST OK [0.003 secs, 4284 KB]
   Test 6: TEST OK [0.003 secs, 4284 KB]
   Test 7: TEST OK [0.011 secs, 4548 KB]
   Test 8: TEST OK [0.059 secs, 5736 KB]
   Test 9: TEST OK [0.003 secs, 4284 KB]

All tests OK.

用map,最慢0.059


/*
TASK:fracdec
LANG:C++
*/

#include <cstdio>
#include <map>
using namespace std;

int n, m, t = 0, zifu = 0;
int a[100000]={0}, b[100000];
map<int, int>q;
map<int, int>::iterator it;

inline void cal()
{
	++zifu;
	if (zifu == 76)
	{
		zifu = 0;
		putchar('\n');
	}			
	return ;
}

int main()
{
	freopen("fracdec.in","r",stdin);
	freopen("fracdec.out","w",stdout);
	scanf("%d%d",&n, &m);
	while (n)
	{
		a[t ++] = n % 10;	
		n /= 10;
	}
	for (int i = 0; i <= (t - 1) / 2; ++ i)	swap(a[i], a[t - i - 1]);
	int p = 0, i, tot =0, tmp;	
	bool flag = false;
	while (1)
	{
		tot = tot * 10 + a[p];
		b[p] = tot / m;
		tot %= m;
		if (p > t - 2)
		{
			it = q.find(tot);	
			if (it != q.end())
			{
				flag = true;
				tmp = q[tot];
				break;	
			}
			q[tot] = p;
		}
		++ p;
		if (tot == 0 && p >=t)	break;
	}

	/*处理整数部分输出*/
	for (i = 0; i != t; ++ i)
		if (b[i])	break;	
	if (i == t)
	{
		putchar('0');
		++zifu;
	}


	if (!flag) //非循环小数
	{
		for (; i < p; ++ i)	
		{
			if (i == t)	
			{
				putchar('.');
				cal();
			}
			putchar(b[i] + '0');
			cal();
		}
		if (i == t)	
		{
			putchar('.');	cal();
			putchar('0');	cal();
		}
	}else{

		for (; i <= p; ++ i)	
		{
			if (i == t)	
			{
				putchar('.');
				cal();
			}
			if (i == tmp + 1)	
			{
				putchar('(');
				cal();
			}
			putchar(b[i] + '0');
			cal();
		}
		putchar(')');
		cal();
	}
	putchar('\n');
	return 0;	
}


改成vis数组判定后速度飞快。 最慢0.016ms 比map快了4倍这样

Executing...
   Test 1: TEST OK [0.008 secs, 4540 KB]
   Test 2: TEST OK [0.005 secs, 4540 KB]
   Test 3: TEST OK [0.008 secs, 4540 KB]
   Test 4: TEST OK [0.005 secs, 4540 KB]
   Test 5: TEST OK [0.008 secs, 4540 KB]
   Test 6: TEST OK [0.008 secs, 4540 KB]
   Test 7: TEST OK [0.011 secs, 4540 KB]
   Test 8: TEST OK [0.016 secs, 4540 KB]
   Test 9: TEST OK [0.008 secs, 4540 KB]

All tests OK.
/*
TASK:fracdec
LANG:C++
*/

#include <cstdio>
#include <cstring>

int n, m, t = 0, zifu = 0;
int a[100000]={0}, b[100000];
int vis[100005];

inline void swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

inline void cal()
{
	++zifu;
	if (zifu == 76)
	{
		zifu = 0;
		putchar('\n');
	}			
	return ;
}

int main()
{
	freopen("fracdec.in","r",stdin);
	freopen("fracdec.out","w",stdout);
	scanf("%d%d",&n, &m);
	memset(vis, -1, sizeof(vis));
	while (n)
	{
		a[t ++] = n % 10;	
		n /= 10;
	}
	for (int i = 0; i <= (t - 1) / 2; ++ i)	swap(a[i], a[t - i - 1]);
	int p = 0, i, tot =0, tmp;	
	bool flag = false;
	while (1)
	{
		tot = tot * 10 + a[p];
		b[p] = tot / m;
		tot %= m;
		if (p > t - 2)
		{
			if (vis[tot] != -1)
			{
				flag = true;
				tmp = vis[tot];
				break;	
			}
			vis[tot] = p;
		}
		++ p;
		if (tot == 0 && p >=t)	break;
	}

	/*处理整数部分输出*/
	for (i = 0; i != t; ++ i)
		if (b[i])	break;	
	if (i == t)
	{
		putchar('0');
		++zifu;
	}


	if (!flag) //非循环小数
	{
		for (; i < p; ++ i)	
		{
			if (i == t)	
			{
				putchar('.');
				cal();
			}
			putchar(b[i] + '0');
			cal();
		}
		if (i == t)	
		{
			putchar('.');	cal();
			putchar('0');	cal();
		}
	}else{

		for (; i <= p; ++ i)	
		{
			if (i == t)	
			{
				putchar('.');
				cal();
			}
			if (i == tmp + 1)	
			{
				putchar('(');
				cal();
			}
			putchar(b[i] + '0');
			cal();
		}
		putchar(')');
		cal();
	}
	putchar('\n');
	return 0;	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值