[USACO3.2] 阶乘问题
Luogu P1134 [USACO3.2] 阶乘问题
首先,可以看到:-这道题的标签是数学-
于是乎,
数学 启动!
首先,我想到了 找规律 :
以每十个数(即 \(1\) ~ \(10\) , \(11\) ~ \(20\) , \(\dots\) )为单位,可以发现,每十个数相乘后的个位数为 \(0\) , 显然是不符合题意的
然后,我又想到了,\(2 \times 5=10\) 和 \(10\) 会影响结果末尾的 \(0\) 的个数,于是,我舍弃了 \(2,5,10\) 然后得到了每十个数(实际上是 \(7\) 个)相乘后末尾的数是 \(8\) (事实上这好像是错的,因为我实际上只算了 \(1\) ~ \(10\) ),然后对于每一组( \(10\) 个),显然答案是 \(8^{整组数} \times 剩余的几个数(排除 2,5,1)\)
显然,这是错的
于是乎,我写了暴力
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
long long ans = 1;
for (int i = 1; i <= n; ++i)
{
ans = ans * i;
while (ans % 10 == 0)
ans = ans / 10;
}
cout << ans % 10 << '\n';
return 0;
}

长达五分钟的思考时间

于是乎
我想到了因为除了 \(10=2\times 5\) , \(2\) , \(5\) 以外,还有 \(25=5\times 5\) (有两个因子 \(5\) ),\(8=2^3\) , \(6=2\times 3\) (也有一个因子 \(2\) )
接着,我想到了可以统计因子 \(2,5\) 的个数,最终答案就是所有数除去因子 \(2,5\) 后的乘积 \(\times\)(因子\(2\) 的个数 \(>\) 因子 \(5\) 的个数 \(?\) \(2^{因子 2 的个数-因子5的个数}\) \(:\) \(5^{因子5的个数-因子2的个数}\) )
显然“ \(\times\) ” 后面的这个东西可以直接快速幂,
蛋柿 \(\dots\)
我-又想到了-既然只有 \(2\) 和 \(5\) , 何必要用快速幂呢,直接用数组存得了,于是乎,
#include <iostream>
#include <algorithm>
using namespace std;
int cnter, cntwu;
int er[(int)5e6 + 10];
int wu[(int)5e6 + 10];
int main()
{
int n;
cin >> n;
long long ans = 1;
er[0] = 1;
for (int i = 1; i <= 5e6; ++i)
{
er[i] = er[i - 1] * 2 % 10;
}
wu[0] = 1;
for (int i = 1; i <= 5e6; ++i)
{
wu[i] = wu[i - 1] * 5 % 10;
}
for (int i = 1; i <= n; ++i)
{
int k = i;
while (k % 2 == 0 && k > 0)
{
k /= 2;
cnter++;
}
// k = i;
while (k % 5 == 0 && k > 0)
{
k /= 5;
cntwu++;
}
cnter -= min(cnter, cntwu);
cntwu -= min(cntwu, cnter);
ans = ans * k % 10;
}
if (cnter == cntwu && cnter == 0)
{
cout << ans % 10 << '\n';
}
else if (cnter > 0)
{
cout << ans * er[cnter] % 10 << '\n';
}
else
{
cout << ans * wu[cntwu] % 10 << '\n';
}
return 0;
}

又是长达 \(10 \min\) 的调整
(我改了数组的大小为 \(2e7 +10\) , 全部 \(TLE\))
(甚至还改了数组为 \(short\) 类型 , 还是 \(RE\) 一个点 )
(然后,我想到:-既然数组会炸,那为何不用快速幂呢-)
于是乎
#include <iostream>
#include <algorithm>
using namespace std;
int cnter, cntwu;
long long ksm(int a, int b, int p)
{
if (b == 0)
{
return 1 % p;
}
if (b == 1)
{
return a % p;
}
long long ans = ksm(a, b / 2, p);
ans = 1ll * ans * ans % p;
if (b % 2)
{
ans = 1ll * ans % p * a % p;
}
return ans;
}
int main()
{
int n;
cin >> n;
long long ans = 1;
for (int i = 1; i <= n; ++i)
{
int k = i;
while (k % 2 == 0 && k > 0)
{
k /= 2;
cnter++;
}
// k = i;
while (k % 5 == 0 && k > 0)
{
k /= 5;
cntwu++;
}
cnter -= min(cnter, cntwu);
cntwu -= min(cntwu, cnter);
ans = ans * (k % 10) % 10;
}
if (cnter == cntwu && cnter == 0)
{
cout << ans % 10 << '\n';
}
else if (cnter > 0)
{
cout << ans * ksm(2, cnter, 10) % 10 << '\n';
}
else
{
cout << ans * ksm(5, cntwu, 10) % 10 << '\n';
}
return 0;
}


浙公网安备 33010602011771号