河南萌新联赛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;
}
posted @ 2025-07-25 16:44  Lordreamland  阅读(28)  评论(1)    收藏  举报