hdu6125 Free from square 分组背包+状态压缩

/**
题目: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;
}

 

posted on 2017-08-18 13:38  hnust_accqx  阅读(186)  评论(0编辑  收藏  举报

导航