hdu 6125 状压dp+分组
一道玄学题...
其实一开始想的是对的,优化一下就好了
首先我们会发现,乘积不能被完全平方数整除等价于所有因子的每个质因子个数和都至多为1
可是500以内的质数很多,全找出来会爆炸的
可我们会发现,如果一个数的平方会在500以内,那么这个数一定<=22!
所以,1~500中会存在的完全平方数的质因子一定在22以内
这些质数只有八个,所以我们可以找出来
至于剩下的部分,显然23和46是不嫩同时出现的,所以我们把含有23这个因子的所有数分到一个背包里,对每个背包只允许使用其中的一个数,这样就能满足23等只出现一次,对其他更大的质数也是同理
什么?你说会不会重?
23*23>500,那么剩下所有的乘积都大于500,也就是说如果我们只用23及以上的质数分组,每组中的元素是互不重叠的。
什么?你说前面几个小的质数怎么办?
状压啊!
求出每个数对于前面八个质数(是的,小于23的质数有8个,分别为2,3,5,7,11,13,17,19),而言质因子的状态,用二进制表示(如15的质因子状态可以表示为110,即0个2,1个3,一个5)
至于那些用大质数表示不了的数,我们把他们每个单独分包即可。
在转移的时候,我们就可以第一层:枚举所有包,第二层:枚举包中每个元素,第三层:枚举前八个质数的所有状态,第四层:枚举前面用过的数的个数
这样就可以实现转移了,因为每次转移都是上一个包向下一个包去转移,所以包中元素是没有重复的。
当然,我本人在写代码的时候,选择把所有不能分到其他包里的元素全分到第一个包里,然后单独处理第一个包。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define mode 1000000007
using namespace std;
int cnt=;
int pri[];
bool vis[];
ll dp[][(<<)+][];
int sit[];
bool used[];
int bag[][];
int cct[];
int posi[];
int n,k;
void init()
{
for(int i=;i<=;i++)
{
if(!vis[i])
{
pri[cnt++]=i;
}
for(int j=;j<cnt&&i*pri[j]<=;j++)
{
vis[i*pri[j]]=;
if(!i%pri[j])
{
break;
}
}
}
}
void get_bag()
{
bag[][++cct[]]=;
for(int i=;i<=;i++)
{
bool flag=;
for(int t=;t<cnt&&i>=pri[t];t++)
{
if(i%pri[t]==)
{
cct[t-]++;
flag=;
bag[t-][cct[t-]]=i;
break;
}
}
if(!flag)
{
cct[]++;
bag[][cct[]]=i;
}
}
}
void get_ori()
{
sit[]=;
for(int i=;i<=;i++)
{
int t=i;
for(int j=;j<;j++)
{
int cot=;
while(t%pri[j]==)
{
t/=pri[j];
cot++;
}
if(cot>=)
{
used[i]=;
break;
}else if(cot==)
{
sit[i]|=(<<j);
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
init();
get_ori();
get_bag();
while(T--)
{
scanf("%d%d",&n,&k);
memset(dp,,sizeof(dp));
dp[][][]=;
int now=,past=;
for(int i=;i<=cct[];i++)
{
memset(dp[now],,sizeof(dp[now]));
for(int j=;j<(<<);j++)
{
for(int t=;t<=k;t++)
{
dp[now][j][t]=dp[past][j][t];
}
}
for(int j=;j<(<<);j++)
{
for(int t=;t<k;t++)
{
if(!(sit[bag[][i]]&j)&&!used[bag[][i]]&&bag[][i]<=n)
{
dp[now][j|sit[bag[][i]]][t+]+=dp[past][j][t];
dp[now][j|sit[bag[][i]]][t+]%=mode;
}
}
}
swap(now,past);
}
for(int i=;i<=cnt-;i++)
{
memset(dp[now],,sizeof(dp[now]));
for(int j=;j<(<<);j++)
{
for(int t=;t<=k;t++)
{
dp[now][j][t]=dp[past][j][t];
}
}
for(int f=;f<=cct[i];f++)
{
for(int j=;j<(<<);j++)
{
for(int t=;t<k;t++)
{
if(!(sit[bag[i][f]]&j)&&!used[bag[i][f]]&&bag[i][f]<=n)
{
dp[now][j|sit[bag[i][f]]][t+]+=dp[past][j][t];
dp[now][j|sit[bag[i][f]]][t+]%=mode;
}
}
}
}
swap(now,past);
}
ll ans=;
for(int i=;i<(<<);i++)
{
for(int j=;j<=k;j++)
{
ans+=dp[past][i][j];
ans%=mode;
}
}
printf("%lld\n",ans%mode);
}
return ;
}
hdu 6125 状压dp+分组的更多相关文章
- NOI 2015 寿司晚宴 (状压DP+分组背包)
题目大意:两个人从2~n中随意取几个数(不取也算作一种方案),被一个人取过的数不能被另一个人再取.两个人合法的取法是,其中一个人取的任何数必须与另一个人取的每一个数都互质,求所有合法的方案数 (数据范 ...
- HDU 4778 状压DP
一看就是状压,由于是类似博弈的游戏.游戏里的两人都是绝对聪明,那么先手的选择是能够确定最终局面的. 实际上是枚举最终局面情况,0代表是被Bob拿走的,1为Alice拿走的,当时Alice拿走且满足变换 ...
- NOIP模拟 乘积 - 状压dp + 分组背包
题目大意: 给出n和k,求从小于等于n的数中取出不超过k个,其乘积是无平方因子数的方案数.无平方因子数:不能被质数的平方整除. 题目分析: 10(枚举\(n\le8\)),40(简单状压\(n\le1 ...
- HDU - 6125: Free from square (状压DP+分组背包)
problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...
- HDU 3001 状压DP
有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路 成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到 ...
- hdu 2809(状压dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2809 思路:简单的状压dp,看代码会更明白. #include<iostream> #in ...
- hdu 2167(状压dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2167 思路:经典的状压dp题,前后,上下,对角8个位置不能取,状态压缩枚举即可所有情况,递推关系是为d ...
- Engineer Assignment HDU - 6006 状压dp
http://acm.split.hdu.edu.cn/showproblem.php?pid=6006 比赛的时候写了一个暴力,存暴力,过了,还46ms 那个暴力的思路是,预处理can[i][j]表 ...
- hdu 3254 (状压DP) Corn Fields
poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两 ...
随机推荐
- HDU3613 Manacher//EXKMP//KMP
http://acm.hdu.edu.cn/showproblem.php?pid=3613 每个字符都有一个权值,将一个字符串分成两半,如果某一半是回文串就把所有的字符权值加起来,否则当0来处理,问 ...
- MySQL开启远程连接的方法
默认情况下,mysql只允许本地登录,如果要开启远程连接,则需要修改/etc/mysql/my.conf文件. 一.修改/etc/mysql/my.conf找到bind-address = 127.0 ...
- linux系统下安装ruby环境
1. 移除现有 Ruby 默认源 输入以下指令 $gem sources --remove https://rubygems.org/ 2. 使用新的源 输入以下指令 $gem sources -a ...
- Ruby 集合数组常用遍历方法
迭代器简介 先简单介绍一下迭代器. 1.一个Ruby迭代器就是一个简单的能接收代码块的方法(比如each这个方法就是一个迭代器).特征:如果一个方法里包含了yield调用,那这个方法肯定是迭代器: 2 ...
- weblogic11g 修改密码和重置密码【原】
修改密码 知道密码的情况下,可参考该链接 http://www.cnblogs.com/may12138/p/6022946.html 或 http://www.cnblogs.com/lsdb/p/ ...
- Socket 连接建立过程
阻塞模式下: 1,客户端向服务器端发起请求建立连接时,服务器端只需要运行到 serverSocket = ); 客户端注册的 SelectionKey.OP_CONNECT 事件就能够发生. 也就是 ...
- VMware workstation 网络选择 NAT模式 访问外网
多年不用本地做测试 尽然被 nat 模式給卡着了 :动手的还是所以要记录一下: 1.根据自己需求创建 虚拟机 之后: 配置[网络适配器] -- 选择 nat 模式 ( 选择网卡 ) 虚拟机 ...
- js 组件化
我的github样例:https://github.com/hzijone/javascript_module js 用对象的方式实现组件化. 1.对一个对象里增加方法的方式: 把模块的变量传给函数, ...
- Android NetworkInterface 的 name
user@android:/$ ls /sys/class/net/ dummy0 lo p2p0 rev_rmnet0 rev_rmnet1 rev_rmnet2 rev_rmnet3 rmnet0 ...
- Weblogic的安装与卸载
一.下载weblogic 到Oracle官网https://www.oracle.com/downloads/index.html,我在这里下载的是weblogic12C进行安装:https://ww ...