这题我原本的思路是:对n!进行质因数分解,并保存所有质因数。对分解的数求2与5出现次数中的较小者z。剔除z对2 * 5,余下的数相乘并不断%10即可。
但这种方法会TLE+MLE。仔细思考后不难发现:不需要对每个数都质因数分解,只要分解为若干个2与5,剩下的数不分解也可以:
void primeFactor(int n) {
while(n>1) {
if(n%2!=0&&n%5!=0) break;
while(n%2==0) {
n/=2;
f.push_back(2);
}
while(n%5==0) {
n/=5;
f.push_back(5);
}
}
if(n>1) f.push_back(n);
}
void cntZero(int n) {
int two=0,five=0;
f.reserve(n*2);
for(int i=2; i<=n; i++)
primeFactor(i);
int s=f.size();
for(int i=0; i<s; i++) {
if(f[i]==2) two++;
elsif(f[i]==5) five++;
}
int zero=min(two,five),del2=0,del5=0;
for(int i=0; i<s; i++) {
if(del2>=zero&&del5>=zero) break;
if(f[i]==2&&del2<zero) {
del2++;
f[i]=1;
}
elsif(f[i]==5&&del5<zero) {
del5++;
f[i]=1;
}
}
}
但这样仍然会爆空间。有两种优化思路:
- 把res设为全局变量, ≠ 2 & & ≠ 5 \neq2 \&\& \neq 5 =2&&=5 的因子不是放入f中而是直接乘到res上。
- 把two,five设为全局变量,=2 || =5的因子不再放入f中,只做统计。最后若two>=five则乘上4+(two-five)%4个2(通过找规律得出),否则(实际上不可能)直接*5。
将上面的优化结合,就不用f数组了。代码如下:
int two,five,res=1;
void primeFactor(int n) {
while(n>1) {
if(n%2!=0&&n%5!=0)
break;
while(n%2==0) {
n/=2;
two++;
}
while(n%5==0) {
n/=5;
five++;
}
}
if(n>1) res=(res*n)%10;
}
int main() {
int n;
scanf("%d",&n);
if(n<3||n==4)
printf("%d",n); //1,2,4
else {
for(int i=2; i<=n; i++)
primeFactor(i);
//处理2和5
if(two>=five) {
for(int i=0; i<4+(two-five)%4; i++) {
res=(res*2)%10;
}
}
else res=5;
printf("%d",res);
}
return 0;
}