CF2153E题解
改了一个错误。
题意简述
对于
当
再定义
再定义
给定两个正整数
可以保证答案严格小于
分析
首先可以注意到一个东西:假设
那么我们就可以开心地发现,设
接下来考虑剩下的数。可以算出
然后还有一个结论:当
我们再来考虑如果
实际上可以发现,只需要考虑
那么我们暴力枚举就可以解决了。
时间复杂度看似很大,实则能过。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e7+5;
const int INF = 0x3f3f3f3f;
int prime[MAXN], cnt;
bool isnp[MAXN];
int n, m;
inline int v(int p, int x) {
int res = 0;
ll pw_p = p;
for(; pw_p <= x; )
{
res += x / pw_p;
pw_p *= p;
}
return res;
}
inline void init()
{
for(int i = 2; i <= MAXN-5; i++)
{
if(!isnp[i]) { prime[++cnt] = i; }
for(int j = 1; j <= cnt; j++)
{
const ll cur = prime[j];
if(cur * i > MAXN-5) break;
isnp[cur * i] = true;
if(i % cur == 0) break;
}
}
}
inline void solve()
{
ll ans = 0;
scanf("%d%d", &n, &m);
// find the largest prime q <= n.
int p0 = prime[upper_bound(prime + 1, prime + cnt + 1, n) - prime - 1];
vector<int> up; // 存放 p 满足:存在 k 使得 p0 <= p * k <= n 且 p * p > n
for(int f = 1; (ll)f * f <= n; f++)
{
int p = n/f;
p = prime[upper_bound(prime + 1, prime + cnt + 1, p) - prime - 1];
up.emplace_back(p);
}
for(int x = p0; x < n; x++)
{
int res = INF;
for(int p : up)
{
int vx = v(p, x), vn = v(p, n);
if(vx != vn) res = min(vx, res);
}
// 小质数直接枚举
for(int i = 1; i <= cnt; i++)
{
if(prime[i] * prime[i] > m) break;
int p = prime[i];
int bvx = v(p, x), bvn = v(p, n);
for(ll e = 1, curp = p; curp <= m; e++, curp *= p)
{
int vx = bvx / e, vn = bvn / e;
if(vx != vn) res = min(res, vx);
}
}
ans += res;
}
printf("%lld\n", ans);
return;
}
int main()
{
init();
int T;
scanf("%d", &T);
while(T--) solve();
return 0;
}
感谢 @shrimpballs 提出的错误。