CodeForces Manthan, Codefest 16 B A Trivial Problem 二分

题意:找到满足x!的尾部有m个0的所有正整数x

被cmath里的pow函数坑了,,,不明白为什么。。。

找到了那个WA的test,我的VS2013运行就没问题,但是在评测机上就有问题。。。

官方的思路是二分,不过我的不是,,,有时间再贴讲解吧,,感觉我的思路也没什么意思

嗯,先来写写官方的思路,用二分,找到最小的尾部有m个0的数x,然后依次++,一直到尾部的0多于m。

然后,我的思路,,就有点奇葩。

我是先列举5,25,125,625,…他们的阶乘尾部各有多少个0。0的话,是由10组成的,即2*5,只要有5,2是充分足够的5用的。

5的尾部肯定是1个,25的话,5,10,15,20,各会提供一个10,但是25的话,会提供两个0,因为他有两个5,所以一共是6个。

同理,50也会提供2个0,75,100,都是,提供两个0。

125,125会提供三个0,所有是25的倍数的,都会提供两个0,是5的倍数但不是25的倍数的会提供1个0。

也就是说,所有5的倍数的会提供1个0,即一共25个,所有25的倍数的会再提供一个0,即又来5个,然后所有125的倍数的会再提供一个0,又来一个,就是1+5+25=31个。

所以,对于5^i,它的阶乘的尾部的0的个数是,1+5+25+…+5^(i-1)=(5^i-1)/4,好吧,我代码里写的是5^i /4,不过是整除,也不影响结果,但是还是应该改掉。

然后求出来之后,比如要找70个0的,125的阶乘会提供31个0,625提供的0大于70,所以不会超过625。70/31=2,70%31=8,125!可以提供31个0,同样,250*249*...*126,也可以提供31个0。道理都是一样的,只不过125!里出现的是5,10,15,,,,25,50,,75,,100,,125。250!/125!里出现的是130,,135,,140,,150,,175,,200,,,225,,,250,,提供的0都是一样的。所以是250!会提供62个0,然后还剩8个0,25!会提供6个0,然后再加个25,就是275,然后还剩两个0,10!会提供两个0,所以再加个10,就是285。这个讲的就是我的work函数。当然还有无法组成的情况,比如恰有5个0的,5的阶乘会提供1个0,就是5*5,但是5*5,的后面这个系数5,会再提供一个0,所以,假如除了之后的商是5,那就是无法组成的。。。

唉,,,本来很简单一个二分+暴力找的题,活生生被我搞得这么复杂。。智商捉急。。


再来看看怎么求一个数的阶乘的尾部有多少个0。

inline int get(int n) {
	int z = 0;
	while (n > 0) {
		n /= 5;
		z += n;
	}
	return z;
}

这是t神的代码,跟我上面求5^i的尾部有多少个0的公式其实是一样的,而且因为这里的/是整除,所以即使n不是5的倍数,也没关系。。。然后这个东西再配一个二分就是官方的解答了

这里是我的代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <map>
using namespace std;
int five_pow[10];
int zero_num[100000];
int ans = 0;
int powi(int a, int b)
{
	int ans = 1;
	for (int i = 0; i < b; ++i)
		ans *= a;
	return ans;
}
bool work(int m, int i)
{
	if (m == 0)
		return true;
	int t = powi(5, i);
	if (m >= five_pow[i])
	{
		int n = m%five_pow[i];
		int t1 = m / five_pow[i];
		if (t1 >= 5)
			return false;
		ans += t1 * t;
		m = n;
	}
	return work(m, i - 1);
}
int main()
{
	int m;
	scanf("%d", &m);
	for (int i = 1; i < 10; ++i)
		five_pow[i] = (powi(5, i) - 1) / 4;
	if (work(m, 8))
	{
		printf("5\n");
		for (int i = 0; i < 5; ++i)
		{
			if (i > 0)
				printf(" ");
			printf("%d", ans + i);
		}
	}
	else
		printf("0");
	printf("\n");
	//printf("ans %d\n", ans);
	//while (1);
	return 0;
}

你可能感兴趣的:(CodeForces Manthan, Codefest 16 B A Trivial Problem 二分)