题目大意:让你在1~n中选择不多于k个数(n,k<=500),保证它们的乘积不能被平方数整除。求选择的方案数

因为质数的平方在500以内的只有8个,所以我们考虑状压

先找出在n以内所有平方数小于等于n的质数,然后我们把它们作为状压的状态

然后要对每个小于n数进行状压,如果它不能被它能被质数的平方整除,那就筛出它所有的在状态内的质因子,大于状态内的质因子我们存到剩余因子的乘积的部分里

比如46,它的状态可以表示成0000 0001 (19,17,13,11,7,5,3,2)  46/2=23,把它存到23的0000 0001状态里

这么做之后,你会惊奇的发现,每个数字只被存到了一个地方,且只被存了一次!

而这也是分组背包可行的关键

下一步就是分组背包了

我们从1遍历到n,遍历所有状态,如果存了,意味着这个状态表示的数可以选一个,就++

然后枚举上一层进行转移即可

细节可以看代码

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define N 100
#define M 505
#define maxn (1<<8)+5
#define ll long long
#define mod 1000000007
using namespace std; int T,n,m,cnt,K;
ll f[][M][maxn],tmp[M][maxn];
int p[M],ok[M],pr[M],can[M][maxn],use[M];
int a[]={,,,,,,,,,};
vector<int>to[M];
void clr()
{
for(int i=;i<M;i++) to[i].clear();
memset(p,,sizeof(p));
memset(ok,,sizeof(ok));
memset(pr,,sizeof(pr));
memset(can,,sizeof(can));
memset(use,,sizeof(use));
memset(f,,sizeof(f));
cnt=;
}
void get_P()
{
for(int i=;i<=n;i++)
{
if(!use[i]) pr[cnt++]=i;
for(int j=;j<cnt&&i*pr[j]<=n;j++){
use[i*pr[j]]=;
if(i%pr[j]==) break;}
}
for(int i=;i<=n;i++)
{
int x=i,ps=;
for(int j=;j<min(K,);j++)
if(x%(pr[j]*pr[j])==) {
ok[i]=-,p[i]=;
break;
}else if(ok[i]!=-&&x%pr[j]==)
{
p[i]|=(<<j);
x/=pr[j];
}
if(ok[i]!=-)
{
if(x!=) to[x].push_back(i);
else to[i].push_back(i);
}
}
for(int i=;i<=n;i++) //can数组表示i是否存了能用某个二进制质因子表示的数
{
if(ok[i]==-) continue;
for(int j=;j<to[i].size();j++)
can[i][p[to[i][j]]]=;
}
} int main()
{
//freopen("aa.in","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
clr();
K=;
while(K+<=&&a[K+]*a[K+]<=n) K++;
get_P();
int y=,x=;
for(int i=;i<=n;i++){ //分组背包
if(!to[i].size()) continue;
for(int s1=;s1<(<<K);s1++)
for(int j=;j<=m;j++)
f[y][j][s1]=f[x][j][s1];
for(int s1=;s1<(<<K);s1++)
{
if(!can[i][s1]) continue;
f[y][][s1]=(f[y][][s1]+)%mod;
//如果i的状态里有s1,那么说明这个状态表示的数可以直接被选,就++
for(int j=;j<=m;j++)
for(int s2=;s2<(<<K);s2++)
{
if(s1&s2) continue;
f[y][j][s1|s2]+=f[x][j-][s2];
f[y][j][s1|s2]%=mod;
}
}
swap(y,x);
}
ll ans=;
for(int s=;s<(<<K);s++)
for(int j=;j<=m;j++)
ans=(ans+f[x][j][s])%mod;
printf("%lld\n",ans);
}
return ;
}

HDU 6125 Free from square (状压DP+分组背包)的更多相关文章

  1. HDU 6125 Free from square (状压DP+背包)

    题意:问你从 1 - n 至多选 m 个数使得他们的乘积不能整除完全平方数. 析:首先不能整除完全平方数,那么选的数肯定不能是完全平方数,然后选择的数也不能相同的质因子. 对于1-500有的质因子至多 ...

  2. HDU 6125 Free from square 状态压缩DP + 分组背包

    Free from square Problem Description There is a set including all positive integers that are not mor ...

  3. NOI 2015 寿司晚宴 (状压DP+分组背包)

    题目大意:两个人从2~n中随意取几个数(不取也算作一种方案),被一个人取过的数不能被另一个人再取.两个人合法的取法是,其中一个人取的任何数必须与另一个人取的每一个数都互质,求所有合法的方案数 (数据范 ...

  4. NOIP模拟 乘积 - 状压dp + 分组背包

    题目大意: 给出n和k,求从小于等于n的数中取出不超过k个,其乘积是无平方因子数的方案数.无平方因子数:不能被质数的平方整除. 题目分析: 10(枚举\(n\le8\)),40(简单状压\(n\le1 ...

  5. HDU - 6125: Free from square (状压DP+分组背包)

    problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...

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

    http://acm.hdu.edu.cn/showproblem.php?pid=6125 题意: 在${1,2,3,...n}$的数中选择1~k个数,使得它们的乘积不能被平方数整除(1除外),计算 ...

  7. 树形DP和状压DP和背包DP

    树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...

  8. HDU 6149 Valley Numer II 状压DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意:中文题目 解法:状压DP,dp[i][j]代表前i个低点,当前高点状态为j的方案数,然后枚 ...

  9. HDU 5434 Peace small elephant 状压dp+矩阵快速幂

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant  Accepts: 38  Submissions: ...

随机推荐

  1. 【JavaScript框架封装】实现一个类似于JQuery的属性框架的封装

    // 属性框架 (function (xframe) { // 需要参与链式访问的(必须使用prototype的方式来给对象扩充方法) xframe.extend({ /** * 获取/设置某一个元素 ...

  2. VUE 利用 webpack 给生产环境和发布环境配置不同的接口地址

    转载地址: https://blog.csdn.net/gebitan505/article/details/58166055 VUE 利用 webpack 给生产环境和发布环境配置不同的接口地址 前 ...

  3. [SPOJ1716] GSS3 - Can you answer these queries III

    线段树操作. 维护一个区间最大连续子段和,左最大连续子段和,右最大连续子段和即可. 最后不知道怎么搞,query的时候返回了个结构体. #include <cstdio> #include ...

  4. [剑指offer] 49. 丑数

    通俗易懂的解释: 首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,那 ...

  5. Java工具类使用注意事项

    (以下摘自阿里巴巴Java开发手册) 1. [强制]获取单例对象需要保证线程安全,其中的方法也要保证线程安全. 说明:资源驱动类.工具类.单例工厂类都需要注意. 5. [强制]SimpleDateFo ...

  6. C和C++ const的声明差异

    当在C源代码文件中将变量声明为const时,可以通过以下方式实现: const int i = 2; 然后,可以在另一个模块中使用此变量,如下表示: extern const int i; 但若要获取 ...

  7. Android Drawable 那些不为人知的高效使用方法

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43752383,本文出自:[张鸿洋的博客] 1.概述 Drawable在我们平时的 ...

  8. XCODE插件 之 Code Pilot 无鼠标化

    什么是Code Pilot? Code Pilot 是一个 Xcode 5 插件.同意你不许使用鼠标就能高速地查找项目内的文件.方法和标识符. 它使用模糊查询匹配(fuzzy query matchi ...

  9. 本地自旋锁与信号量/多服务台自旋队列-spin wait风格的信号量

    周日傍晚,我去家附近的超市(...)买苏打水,准备自制青柠苏打.我感觉我做的比买的那个巴黎水要更爽口.由于天气太热,非常多人都去超市避暑去了,超市也不撵人,这仿佛是他们的策略.人过来避暑了,走的时候难 ...

  10. linux虚拟机网络设置好ping百度没有用

    场景:公司内网,本机使用的是本地连接,不是wiff,虚拟机设置了桥接模式 问题:使用桥接模式 启动好网络服务,查看ifconfig也获取到了设置的ip,可是ping了www.baidu.com还是没有 ...