C(等差数列)
idol!!
https://ac.nowcoder.com/acm/contest/57360/C
C.idol!!
题目大意:
求解:1!!* 2!!······ n!! 的值末尾0的个数;
题意转化:
末尾0的个数就是几个10的相乘,就是10的个数,由于10=2*5,所以就是求解质因数2和5的个数;但由于2一定比5多,所以就直接转化为求解5的个数;
比赛的时候想到了等差数列求解5的个数,竟然没想到5的次方的个数咋求解;
题解思路:
先说下如何采用等差数列求解5的个数;
分两种情况:求解奇数中5的个数,求解偶数中5的个数
对于奇数:
对于偶数:
暂时先不考虑5的次方的情况(就是一个数中包含几个5的情况,比如说25)很容易看出来就是首项为5,公差为5的等差数列;
所以单纯求5的个数的代码如下:
void solve()
{
cin>>n;
int sum1=n/2+1-2,sum2=n/2-4;//求需要求的奇数和偶数的个数
int cnt1=sum1/5,cnt2=sum2/5;//求等差数列求和的项数
int n1=sum1%5,n2=sum2%5;//单独多出来的几项
int ans1=0,ans2=0;
ans1+=5*(1+cnt1)*cnt1/2,ans2+=5*(1+cnt2)*cnt2/2;//等差数列求和,首项加末项乘以项数除以2
ans1+=(cnt1+1)*n1, ans2+=(cnt2+1)*n2; //加上多余的几项,多余的几项肯定比前几项最后一个大一
if(sum1<0) ans1=0;
if(sum2<0) ans2=0;
cout<<ans1+ans2<<endl;
}
再思考要是有25,50,75,125一个数中含有多个5的情况,该如何求解;
例如:对于25以后的数都会含有25,多以都会含有5^2;一下只考虑5^2的情况的个数为
举完例子后发现是25个数后才会多出一个5^2,因为这时候才会出现一个25的倍数,
这种情况就为以25为首项,25为公差的等差数列;同理可得偶数的情况也是同样的;
那么只需要依次求解出5,5^2,5^3···的个数和就是答案,记录第一次出现的位置就可以了,然后用n-第一次出现的位置就知道对应的情况有多少个数了,然后同样用求解5的个数的方法求解其他情况即可;
代码如下:
#define int128 __int128_t
void print(int128 x){
if(x<0)x=-x,putchar('-');
if(x>9)print(x/10);
putchar(x%10+'0');
}
int128 sub(int128 n,int128 k){
int128 cur=1,w=1,ans=0;
while(1){
w*=5;
cur=cur*5-k;//难点,这个可能比较难想到,但可以换种写法一样的,比如说偶数是w,奇数就是(w+1)/2,w就是上面那个w
if(cur>n) break;
int128 cnt=(n-cur+1)/w;//等差数列求和
int128 sum=(n-cur+1)%w;
ans+=w*(1+cnt)*cnt/2;
ans+=(cnt+1)*sum;
}
return ans;
}
void solve(){
cin>>n;
int128 ans=0;
ans+=sub(n/2,0);
ans+=sub((n+1)/2,2);
print(ans);
}