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,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两 ...
随机推荐
- How the Bitcoin protocol actually works
sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...
- bash变量详解
bash变量详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 大家都知道Shell是一门脚本语言,脚本语言的最好的优点就是我们写的代码不需要编辑就可以直接运行,当然你也可以把它归 ...
- brctl创建虚拟网卡详解
brctl创建虚拟网卡详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 很久之前我分享过一篇关于搭建Openvpn的笔记,在笔记的最后我分享了一个脚本,是用来创建虚拟网卡的,今天 ...
- 多目标遗传算法 ------ NSGA-II (部分源码解析)目标函数 problemdef.c
/* Test problem definitions */ # include <stdio.h> # include <stdlib.h> # include <ma ...
- rabbitmq用户授权
创建用户 rabbitmqctl add_user kye01 123456 设置用户角色 rabbitmqctl set_user_tags kye01 monitoring 查看用户清单 rabb ...
- GYM 101173 K.Key Knocking(构造)
原题链接 参考自 问题描述:一个长度为3*n的01串,每次可以翻转连续的两个字符,要求至多翻转n次使得这个3*n的串至少有2*n个连续的段且相邻两端不一样(就是连续的0算一段,然后连续的1,…) 解法 ...
- java抽象类与接口回顾
1.抽象类中可以包括成员变量,方法,构造器,初始化块,内部类(接口/枚举)五种成分.2.让A类中包含B方法,又不提供B方法的实现,即抽象方法只有方法签名,没有方法体.3.有抽象方法的类只能被定义成抽象 ...
- npm webpack工具 (监听压缩等)
压缩.监听变动自动打包,:开发后,js编译压缩及样式去空格等 $ webpack --config XXX.js //url使用另一份配置文件(比如webpack.config2.js)来打包 $ w ...
- 网站程序CMS识别
CMS cms一般有dedecms(织梦),dzcms,phpweb,phpwind,phpcms,ecshop,dvbbs,siteweaver,aspcms,帝国,zblog,wordpress等 ...
- QDialog对话框
QDialog对话框,用来实现那些只是暂时存在的用户界面,是独立的窗口,但通常也有父窗口对话框有模态和非模态两种,,非模态对话框的行为和使用方法都类似于普通的窗口,模态对话框则有所不同,当模态对话框显 ...