河南萌新联赛2025第(二)场:河南农业大学 E.咕咕嘎嘎!!!(easy)
传送门
容斥。
枚举\(m\)个数的\(gcd\)为\(i\),累加从含有\(i\)作为因子的数中选取\(m\)个数的方案数。
然而会重复计算。比如含有\(6\)为因子的,也是含有\(2\)作为因子的,也是含有\(3\)作为因子的,于是需要容斥。
然后可以发现,这个容斥系数刚好是莫比乌斯函数取反。
或者最后把答案取个反也行。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pp pop_back
#define pb push_back
#define ins insert
#define lowbit(x) x & -x
const int N = 5010;
const int mod = 1e9 + 7;
const ll INF = 1e18;
int read(){int x; scanf("%d", &x); return x; }
ll readll(){ll x; scanf("%lld", &x); return x; }
int n, m, Mob[N], vis[N], p[N];
ll c[N][N];
signed main(){
n = read(), m = read();
c[0][0] = 1;
for(int i = 1; i <= n; i++){
for(int j = 0; j <= n; j++){
if(i && j) c[i][j] = c[i - 1][j - 1];
if(i) c[i][j] += c[i - 1][j];
c[i][j] %= mod;
}
}
int tt = 0;
Mob[1] = 1;
for(int i = 2; i <= n; i++){
if(! vis[i]) p[++tt] = i, Mob[i] = -1;
for(int j = 1; j <= tt && i * p[j] <= n; j++){
vis[i * p[j]] = 1;
Mob[i * p[j]] = Mob[i] * Mob[p[j]];
if(i % p[j] == 0){
Mob[i * p[j]] = 0;
break;
}
}
}
ll res = 0;
for(int i = 2; i <= n; i++){
(res += Mob[i] * c[n / i][m] % mod) %= mod;
}
cout << -res;
return 0;
}
$\color{blue} \mathcal {Lordreamland}$

浙公网安备 33010602011771号