设 x=∏pqii x = ∏ p i q i , d=gcd(qi) d = g c d ( q i )
若 d>1 d > 1 ,我们先不考虑它。
若 d=1且x>n−−√ d = 1 且 x > n ,则 xy x y 一定不会与其他有重的,贡献为B。
若 d=1且x<=n−−√ d = 1 且 x <= n ,设 L=lognx L = l o g x n ,显然对于L一样的贡献是一样。
由于 (xy)z=xyz ( x y ) z = x y z ,所以问题转换为 x∈[1..L],y∈[1..B] x ∈ [ 1.. L ] , y ∈ [ 1.. B ] ,xy有多少不同取值。
划分一下范围变成问 [1..L∗B] [ 1.. L ∗ B ] 有多少数满足有至少一组xy=它,这个可以想到用容斥原理做,大概要维护lcm和最小的选了的数。
但是L最大是 29 29 ,会超时。
注意 lcm(1−29) l c m ( 1 − 29 ) 的约数个数不多,也就是说可能的lcm个数不多,于是按DAG顺序dp,复杂度就降了下来。
还有一种想法是分块考虑。
枚举i,当前块是 ((i−1)∗B,i∗B] ( ( i − 1 ) ∗ B , i ∗ B ]
显然只有 x∈[i..L] x ∈ [ i . . L ] 的才会对它们产生影响,若一数是 x∈[i..L] x ∈ [ i . . L ] 的倍数,则这个数可以。
当时复杂度好像还是 229 2 29 ,若 [i..L] [ i . . L ] 中有两数d1、d2,满足 d1|d2 d 1 | d 2 ,显然只用保留d1,最大的话还剩15个数。
Code:
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int M = 100000;
int bz[M + 5], p[M + 5], u[M + 5];
int n, m, s[100];
ll ans, sum;
int gcd(ll x, ll y) {return !y ? x : gcd(y, x % y);}
void Shai() {
fo(i, 2, M) {
if(!bz[i]) p[++ p[0]] = i, u[i] = i;
fo(j, 1, p[0]) {
int k = i * p[j];
if(k > M) break;
bz[k] = 1; u[k] = p[j];
if(i % p[j] == 0) break;
}
}
u[1] = 1;
}
void dg(int x, int y, int z) {
if(z == 1) return;
ans --;
fo(j, y, p[0]) {
int k = 1;
for(ll u = (ll) x * p[j]; u <= n; u *= p[j], k ++)
dg(u, j + 1, gcd(k, z));
if(k == 1) return;
}
}
int t, w[M], bx[M];
void dfs(int x, ll lcm, int fu) {
if(x > w[0]) {
if(lcm == 1 && fu == -1) return;
sum += fu * ((ll) t * m / lcm - (ll) (t - 1) * m / lcm);
return;
}
dfs(x + 1, lcm, fu);
dfs(x + 1, lcm * w[x] / gcd(lcm, w[x]), -fu);
}
int main() {
Shai();
scanf("%d %d", &n, &m);
ans = n;
dg(1, 1, 0);
ans = ans * m; ans ++;
fo(i, 2, M) if(i * i <= n) {
int x = i, gd = 0;
while(x > 1) {
int y = u[x], z = 0;
while(x % y == 0) x /= y, z ++;
gd = gcd(gd, z);
}
x = 1; int y = 0;
while((ll) x * i <= n) x *= i, y ++;
if(gd == 1) {
ans -= m;
s[y] ++;
}
} else break;
fo(i, 2, 29) if(s[i]) {
sum = 0;
fo(j, 1, i) {
t = j; w[0] = 0;
fo(k, j, i) bx[k] = 0;
fo(k, j, i) if(!bx[k]) {
w[++ w[0]] = k;
fo(o, 1, i / k) bx[o * k] = 1;
}
dfs(1, 1, -1);
}
ans += sum * s[i];
}
printf("%lld\n", ans);
}