1 条题解
-
0
Written by @Yue_chen
题意:
给定一个 n 和 m,求[1 - n]中 有多少个数的阶乘末尾有m个0。
思路:
注意 n 和 m 很大,思维题 or 数位dp or 矩阵,很显然出题组不会考后面两个( )
直接开玩,枚举发现,每当遇到一个5的倍数,就会多一个0。
ok写完了直接交题。
ok喜提 wa
哦,不小心给0也算进去了,给0删了再交一发。
ok喜提 wa
肯定是我枚举的方法不对,重构一遍代码再交一发。
ok喜提 wa
如果你也红温了评论区请扣111
后来我们发现,25的时候会多出两个0,很简单的道理,两个5,在前面激情wa的可能是小丑吧()
回归正题。
所以我们需要预处理5的所有幂数,然后使用二分去查找第一次出现m个0的数,锁定之后,向后查找5个数(为什么是5个数,因为更多的数一定会遇到新的5)。
把这5个数都check一遍,合法的都加进答案里面。
还有一个坑点,奶奶的这题卡常,给我十连评测都卡出来了,ok喜提tle,在我细节优化之后,也是成功通过了。
时间复杂度O(log5(1e18) * log2n * T)
AC代码:
#include<bits/stdc++.h> using namespace std; using i64 = long long; constexpr i64 N = 1e18; int cnt; i64 p5[1001]; void solve() { i64 n, m; cin>>n>>m; auto check = [&](i64 x) { i64 ans = 0; for(int i=1; i<cnt; ++i) { i64 y = x/p5[i]; if(y == 0) break; ans += y; } return ans; }; i64 l = 0, r = n; while(r-l > 1) { i64 mid = l+r >> 1; if(check(mid) >= m) r = mid; else l = mid; } vector<i64> v; for(i64 i=r; i<=min(n, r+5); ++i) { if(check(i) == m) { v.push_back(i); }else { break; } } if(v.size() == 0) { cout<<"-1\n"; }else { cout<<v.size()<<"\n"; for(auto x: v) { cout<<x<<" "; } cout<<"\n"; } } signed main(void) { ios::sync_with_stdio(false); cin.tie(nullptr); for(i64 i=1; N/i>=5; i*=5) { p5[cnt++] = i; } int t=1; cin>>t; while (t--) solve(); return 0; }
信息
- ID
- 120
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 101
- 已通过
- 5
- 上传者