平方自由数

Problem

多组数据。
给出一个 {1,2,,n} 的全集,从其中选取子集 S,满足:子集大小 |S|k,(至少选择一个数) uSu 是一个平方自由数(square-free integer),即这个数的质因子幂指数均为 1。求满足条件的子集数,对 109+7 取模。

Input

第一行包含一个整数 T(T5),表示数据组数。

对于每组数据,每行包含两个正整数 n,k(n,k500)

Output

对于每组数据,输出一个整数,表示答案。

Sample

Input 1

2
4 2
6 4

Output 1

6
19

Solution

一个平方自由数可以表示成一些质数的乘积,因此可以考虑每一个质因数是否选择。同时发现一个很好的性质,一个 [1,n] 的数最多只有一个质因子 n 个。所以对于 n 以内的质数(8 个),可以状压处理。然后枚举大于 23 的质数,并将它搭配好不超过 23 的若干个质因子,dp 即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int kmax = 505;
const int kmaxM = 8;
const int Mod = 1e9 + 7;

int t, n, k;
bool b[kmax];
int pr[kmax], pc;
long long fac[1 << kmaxM];
long long f[1 << kmaxM][kmax], g[1 << kmaxM][kmax], res; // 前8个质数是否选择,一共选了多少个数

void Prime() { // 筛质数
	b[1] = 1;
	for(int i = 2; i < kmax; i++) {
		if(!b[i]) {
			pr[pc++] = i;
		}
		for(int j = 0; j < pc && i * pr[j] < kmax; j++) {
			b[i * pr[j]] = 1;
			if(i % pr[j] == 0) break;
		}
	}
}

void Mul() {
	for(int i = 0; i < 1 << kmaxM; i++) {
		fac[i] = 1;
		for(int j = 0; j < kmaxM; j++) {
			if(i & (1 << j)) {
				fac[i] = fac[i] * pr[j]; // 计算乘积
			}
		}
	}
}

void Solve() {
	cin >> n >> k;
	memset(f, 0, sizeof(f));
	memset(g, 0, sizeof(g));
	f[0][0] = 1, res = 0;
	for(int i = 0; i < 1 << kmaxM; i++) {
		if(fac[i] > n) continue; // 取值不能超过n
		for(int j = k; j; j--) {
			for(int l = ((1 << kmaxM) - 1) ^ i; ; l = (l - 1) & (((1 << kmaxM) - 1) ^ i)) {
				f[l | i][j] = (f[l | i][j] + f[l][j - 1]) % Mod; // 转移
				if(!l) break;
			}
		}
	}
	for(int t = kmaxM; t < pc; t++) { // 枚举大于23的质数
		memcpy(g, f, sizeof(f));
		for(int i = 0; i < 1 << kmaxM; i++) { // 枚举前8个质数的选择情况
			if(fac[i] * pr[t] > n) continue;
			for(int j = k; j; j--) {
				for(int l = ((1 << kmaxM) - 1) ^ i; ; l = (l - 1) & (((1 << kmaxM) - 1) ^ i)) {
					f[l | i][j] = (f[l | i][j] + g[l][j - 1]) % Mod; // 转移
					if(!l) break;
				}
			}
		}
	}
	for(int i = 0; i < 1 << kmaxM; i++) {
		for(int j = 1; j <= k; j++) {
			res = (res + f[i][j]) % Mod; // 统计结果
		}
	}
	cout << res << '\n';
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	Prime();
	Mul();
	cin >> t;
	while(t--) { // 多组数据
		Solve();
	}
	return 0;
}
posted @   ereoth  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示