奇数的双阶乘等于小于等于本身的奇数的乘积,偶数的双阶乘等于小于等于本身的非零偶数的乘积。
思路:考虑末位0的个数,我们能想到的最小两数相乘有零的就是2*5,所以本题我们思路就是去找因子2的个数以及因子5的个数,2的个数肯定比5的个数,所以我们只需要去找因子5的个数就能知道末位有几个零。这里给个例子:2*15的结果是有一个零,是因为只有一个2和5的因子;4*25的结果末位有两个零,是因为各有两个2和5的因子。
下面主要考虑的就是如何去找5的因子,其实很简单,一个数能被5整除就有1个5的因子,若能被25整除就有两个5的因子,能被整除就有k个5的因子。因为求的是双阶乘的积,举个例子对于5来说,大于等于5的奇数的阶乘都包含5,能求出5~n的奇数个数=,就是5对整个阶乘积贡献的5的个数。由于的倍数包含奇偶,所以要分为奇数偶数讨论,对于所有奇数对总的贡献5的个数都等于本身到n的奇数的个数=
不难发现是个等差数列,这里能求出倍数的项数=,根据项数奇偶性去得出等差数列项数,还能求出等差数列末项,再根据等差数列求和公式就能得出结果。偶数也类似,首项尾项以及项数都能根据奇数情况轻松得到。
要爆longlong!!!!int_128好用
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;
inline void printint(__int128 x)
{if(x>=10) printint(x/10);putchar('0'^(x%10));
}
__int128 a[35];//5的幂 signed main(){int k=0;a[0]=1;while(a[k]*5<=1e18){k++;a[k]=a[k-1]*5;}ll _n;cin>>_n;__int128 n=(__int128)_n;__int128 ans=0;for(int i=1;i<=k&&a[i]<=n;i++){__int128 num=n/a[i];__int128 a1=(n-a[i])/2+1;//首项 __int128 h=a[i]*num;//尾项的值 if(num&&num%2!=0){//先求奇数倍数等差数列 __int128 an=(n-h)/2+1;//尾项 ans+=(num/2+1)*(a1+an)/2;//公式求和 //偶数倍数 首项尾项变 an=(n-h+a[i])/2+1;a1=(n-a[i]*2)/2+1; ans+=(num/2)*(a1+an)/2;}else if(num&&num%2==0) {//先是奇数倍数等差数列 num/=2;a1=(n-a[i])/2+1;//首项 ll an=a[i]*num*2-a[i];an=(n-an)/2+1;//尾项 ans+=num*(a1+an)/2;//偶数 a1=(n-a[i]*2)/2+1;an=(n-a[i]*num*2)/2+1;ans+=(num)*(a1+an)/2; }// cout<<ans<<endl;}printint(ans);
}