文章目录
题意
题目链接
本题大意为 给定m,n
求: P n m P^m_n Pnm的最后一位非0的数
(P在排列组合中就相当于A)
(beican)历程
看到题目 什么都不会的我一脸懵
(洛谷的限制太水了
vjudge上时限1s
我们按严格的来)
但仔细想了一下 我仍然只发现暴力是不可以的
我暴力的思路是 乘起来
但直接乘会爆 就留个9位吧(感觉有点靠运气)
这样的思路肯定是错的 (像这位小哥)
也不要想去优化 不然就像我搞了半天 仍然TLE
接着 再仔细想想 发现求最后一位非0的数 只需要我们在算的过程中除10
又知道 P n m P^m_n Pnm = n ! ( n − m ) ! \frac{n!}{(n -m)!} (n−m)!n! = ∏ i = n − m + 1 n \prod^n_{i=n-m+1} ∏i=n−m+1ni
换言之我们需要将含有因子2和5的除*掉
BTW将因子2和因子5的数量统计
因为一个10是由一个2和一个5乘得得
直接除*掉不能保证因子2与因子5数量相等
需要把多的乘回去(用快速幂)
for(i = n;i > n - m;i--)
{
int j = i;
while(j % 2 == 0)
{
j /= 2;
d2++;
}
while(j % 5 == 0)
{
j /= 5;
d5++;
}
ans = (ans * j) % 10;
}
if(d2 > d5)
More = qkpow(2,d2 - d5);
else if(d5 > d2) More = qkpow(5,d5 - d2);
整体的代码大致如下
#include <cstdio>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
long long d2,d5,More,ans;
inline long long qkpow(int val,int n)
{
long long rest = 1;
while(n)
{
if(n & 1)
rest = val * rest % 10;
val = val * val % 10;
n >>= 1;
}
return rest;
}
int main()
{
int i,n,m;
while(~scanf("%d%d",&n,&m))
{
d2 = d5 = 0;
More = ans = 1;
for(i = n;i > n - m;i--)
{
int j = i;
while(j % 2 == 0)
{
j /= 2;
d2++;