题解 P2231 【[HNOI2002]跳蚤】
相比与楼下诸位的跳跃式思路,我个人比较笨,是用公式一步步推的,给出一个较严格的证明。
每次选一个数跳若干格,这就是所谓的“线性组合”。所以我们可以将问题规约为:如果这
记
考虑到判别函数
此时参数空间满足
改变运算顺序,将
那么这个式子就是非常易于计算的了。
复杂度
#include <cstdio>
#define LOG(FMT...) // fprintf(stderr, "[LOG]: "FMT)
using namespace std;
typedef long long ll;
ll ans;
int n, m, pc;
int p[20];
ll pow(ll x, int k);
void dfs(int ind, int prod, int mu);
int main() {
scanf("%d%d", &n, &m);
int x = m;
for (int d = 2; d * d <= m; ++d) {
if (x % d == 0) {
p[++pc] = d;
while (x % d == 0)
x /= d;
}
}
if (x != 1)
p[++pc] = x;
dfs(1, 1, 1);
printf("%lld\n", ans);
return 0;
}
ll pow(ll x, int k) {
ll ret = 1;
while (k) {
if (k & 1)
ret *= x;
k >>= 1;
x *= x;
}
return ret;
}
void dfs(int ind, int prod, int mu) {
if (ind == pc + 1) {
ans += mu * pow(m / prod, n);
return;
}
dfs(ind + 1, prod, mu);
dfs(ind + 1, prod * p[ind], -mu);
}