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;
}
时间: 2024-10-07 06:33:08

hdu6125 Free from square 分组背包+状态压缩的相关文章

hdu6149 Valley Numer II 分组背包+状态压缩

/** 题目:hdu6149 Valley Numer II 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意: 众所周知,度度熊非常喜欢图. 为了形成山谷,首先要将一个图的顶点标记为高点或者低点. 标记完成后如果一个顶点三元组<X, Y, Z>中, X和Y之间有边,Y与Z之间也有边,同时X和Z是高点,Y是低点,那么它们就构成一个valley. 度度熊想知道一个无向图中最多可以构成多少个valley,一个顶点最多只能出现在一个valley

POJ-2923 Relocation---01背包+状态压缩

题目链接: https://vjudge.net/problem/POJ-2923 题目大意: 有n个货物,给出每个货物的重量,每次用容量为c1,c2的火车运输,问最少需要运送多少次可以将货物运完 思路: 第一次做状态压缩(状态压缩基础知识传送门) 本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品.预处理完能从枚举中找到tot个物品,再用这tol个物品中没有交集(也就是两个状态不能同时含有一个物品)

POJ 2923 【01背包+状态压缩/状压DP】

题目链接 Emma and Eric are moving to their new house they bought after returning from their honeymoon. Fortunately, they have a few friends helping them relocate. To move the furniture, they only have two compact cars, which complicates everything a bit.

HDU 6125 Free from square(状态压缩+分组背包)

http://acm.hdu.edu.cn/showproblem.php?pid=6125 题意: 在${1,2,3,...n}$的数中选择1~k个数,使得它们的乘积不能被平方数整除(1除外),计算有多少种取法. 思路: 考虑一下他们的质因子,如果两个数有相同的质因子,那么它们两个肯定是不能同时选的.这是不是很像分组背包,但是如果以质因子来分类的话,一个数就可能处于多个背包当中,这样就不行了,因为一个数你只能在一个背包中. 这题的数据范围很小,在500的范围内,质数的平方数小于500的就8个数

POJ2923 状态压缩01背包 xingxing在努力

这道题算是很经典的状态压缩01背包了, 题意是有一个人要用两辆小汽车搬家, 每辆小汽车都有一个最大载重量, 现在有一些要搬的家具, 告诉你这些家具的重量, 问最少几次能将这些家具搬完(每次两辆汽车必须出动, 即使有一辆车什么都没有装)? 物品个数不超过10,根据经验一般有10存在的话都要带点暴力的色彩, 那么这道题就是先要预处理所有一次搬走的家具的集合, 然后就将其转化成了01背包的问假设d[i][j]是前i个家具中搬走了j(集合)家具所需要的最少次数那么d[i][j] = min(d[i-1]

TYVJ 2054 [Nescaf&#233;29]四叶草魔杖 最小生成树 状态压缩/背包DP

$ \rightarrow $ 戳我进TYVJ原题 [Nescafé29]四叶草魔杖 题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目背景 陶醉在彩虹光芒笼罩的美景之中,探险队员们不知不觉已经穿过了七色虹, 到达了目的地,面前出现了一座城堡和小溪田园,城堡前的木牌上写着"Poetic Island". "这一定就是另外两位护法的所在地了--我们快进去吧!" 探险队员们快步进入了城堡,城堡大厅的羊毛沙发上

dp状态压缩

dp状态压缩 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了.难点在于以下几个方面:状态怎么压缩?压缩后怎么表示?怎么转移?是否具有最优子结构?是否满足后效性?涉及到一些位运算的操作,虽然比较抽象,但本质还是动态规划.找准动态规划几个方面的问题,深刻理解动态规划的原理,开动脑筋思考问题.这才是掌握动态规划的关键. 动态规划最关键的要处理的问题就是位运算的操作,容易出错,状态的设计也直

HDU 4003 Find Metal Mineral (树形DP,树形分组背包,经典)

题意:给定一棵树图,n个节点,有边权,要派k<11个机器人从节点s出发,遍历所有的点,每当1只机器人经过1条边时就会花费该边的边权,边是可重复走的.问遍历完所有点的最小花费? 思路: 非常经典,首先需要知道一点,才能往下推理.就是“如果在t点派c个机器人往孩子u,那么最多只有1个机器人能走会回来到t,否则花费总是不划算的”. 稍微证明一下: (1)假设派1个机器人往u,逛一圈回到u的父亲t,花费v= 子树u的边权和*2 + e(t,u)*2.若机器人不要了,那花费肯定比v还要少. (2)假设派2

poj 3254 Corn Fields(状态压缩dp)

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and