/** 题目:hdu6125 Free from square 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6125 题意: 从不大于n的所有正整数中选出至少1个且至多k个使得乘积不包含平方因子,对10^9+7取模。 1≤n,k≤500。 思路: 分组背包+状态压缩 把n个数分成若干组,互斥的放在同一组。 一开始把所有含平方因子的数去除掉,剩下的进行分组。 <sqrt(500)的八个素因子,编成八组,分别为包含2,3,5,7,11,13,17,19素因子的数。 注意包含的数不能重复。 >sqrt(500)的素因子,每一组为包含该素因子的数。 1这个数为一组. 因为其他组可能包含2,3,5,7,11,13,17,19;也就是这八个素因子在其他组也可能出现。 为了判断用状态压缩处理。 dp[k][s]表示选k个,前8个素因子选择状态为s时候的方法数。 dp[k][s] += dp[k-1][s-s1]; (s&s1==s1) memset(dp, 0, sizeof dp); dp[0][0] = 1; ans = sigma[1<=i<=m]sigma[0<=s<(1<<8)]dp[i][s]; */ #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <iostream> #include <cmath> #include <vector> #include <map> using namespace std; typedef long long LL; #define ms(x,y) memset(x,y,sizeof x) typedef pair<int, int> P; const int inf = 0x3f3f3f3f; const int mod = 1e9 + 7; const int maxn = 501; int prime[maxn], tot; int pos[20]; vector<P> v[maxn]; int vis[maxn]; LL dp[maxn][1<<8]; void init() { for(int i = 2; i < maxn; i++){ if(prime[i]==0){ for(int j = i*2; j < maxn; j+=i){ prime[j] = 1; } } } tot = 0; for(int i = 2; i < maxn; i++){ if(prime[i]==0){ prime[++tot] = i; } } for(int i = 1; i <= 8; i++){ pos[prime[i]] = i-1; } for(int i = 2; i < maxn; i++){ int x = i; for(int j = 1; j <= tot&&prime[j]<=tot; j++){ int cnt = 0; if(x%prime[j]==0){ while(x%prime[j]==0){ x/=prime[j]; cnt++; } if(cnt>1){ vis[i] = 1; break; } } } } v[0].push_back(P(1,0));///表示1这个数。 for(int i = 9; i <= tot; i++){ for(int j = prime[i]; j < maxn; j+=prime[i]){ if(vis[j]) continue; int s = 0; for(int k = 1; k <= 8; k++){ if(j%prime[k]==0){ s |= (1<<pos[prime[k]]); } } v[i].push_back(P(j,s)); vis[j] = 1; } } for(int i = 1; i <= 8; i++){ for(int j = prime[i]; j < maxn; j+=prime[i]){ if(vis[j]) continue; int s = 0; for(int k = 1; k <= 8; k++){ if(j%prime[k]==0){ s |= (1<<pos[prime[k]]); } } v[i].push_back(P(j,s)); vis[j] = 1; } } } LL solve(int n,int m) { ms(dp,0); dp[0][0] = 1; int len = 1<<8; for(int i = 0; i <= tot; i++){ if(prime[i]>n) break; for(int j = m; j >= 1; j--){ for(int k = 0; k < (int)v[i].size(); k++){ if(v[i][k].first>n) continue; for(int s = 0; s < len; s++){ if((s&v[i][k].second)==v[i][k].second){ dp[j][s] = (dp[j][s]+dp[j-1][s-v[i][k].second])%mod; } } } } } LL ans = 0; for(int i = 1; i <= m; i++) for(int s = 0; s < len; s++) ans = (ans+dp[i][s]) %mod; return ans; } int main() { init(); int T; int n, k; cin>>T; while(T--) { scanf("%d%d",&n,&k); printf("%lld\n",solve(n,k)); } return 0; }
时间: 2024-10-07 06:33:08