题目大意:让你在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. ClipboardJS实现点击复制功能

    <script src="//lib.baomitu.com/clipboard.js/1.7.1/clipboard.min.js"></script> ...

  2. 训练1-o

    给出2个N * N的矩阵M1和M2,输出2个矩阵相乘后的结果. Input 第1行:1个数N,表示矩阵的大小(2 <= N <= 100)第2 - N + 1行,每行N个数,对应M1的1行 ...

  3. CENTOS 7发送邮件测试

    centos7作为126邮箱客户端发送邮件测试. 首先安装客户端软件: yum install sendmail mailx -y 配置邮箱设置: 开启smtp发件协议 配置授权码,写入配置文件. 追 ...

  4. JAVA 上传图片功能

    前后端实现上传图片功能(JAVA代码) 1.前端大概 请求头必须为AJAX请求头: 'X-Requested-With': 'XMLHttpRequest' 一般是指网页中存在的Content-Typ ...

  5. webKit 内核浏览器 源码分析

    如需转载,请注明出处! WebSite: http://www.jjos.org/ 作者: 姜江 linuxemacs@gmail.com QQ: 457283 这是一篇自己写于一年前的工作文档,分享 ...

  6. nyoj 115dijkstar求最短路

    #include<stdio.h> #include<string.h> #define inf 0x3fffffff #define N 1100 int ma[N][N], ...

  7. JS中的call()(转)

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call 方 ...

  8. Eclipse设置jdk相关

    2.window->preferences->java->Compiler->设置右侧的Compiler compliance level 3.window->prefe ...

  9. hdu2476String painter (区间DP)

    Problem Description There are two strings A and B with equal length. Both strings are made up of low ...

  10. HTML5-1、标签

    本文只是自己学习HTML5时的一些笔记.希望自己能够学好HTML5. 如果有感兴趣的同学.可以互相学习. 我觉得HTML5在未来的开发中站主导地位. 下面开始学习HTML5. 还是从HTML5标签开始 ...