一道玄学题...

其实一开始想的是对的,优化一下就好了

首先我们会发现,乘积不能被完全平方数整除等价于所有因子的每个质因子个数和都至多为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+分组的更多相关文章

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

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

  2. HDU 4778 状压DP

    一看就是状压,由于是类似博弈的游戏.游戏里的两人都是绝对聪明,那么先手的选择是能够确定最终局面的. 实际上是枚举最终局面情况,0代表是被Bob拿走的,1为Alice拿走的,当时Alice拿走且满足变换 ...

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

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

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

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

  5. HDU 3001 状压DP

    有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到 ...

  6. hdu 2809(状压dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2809 思路:简单的状压dp,看代码会更明白. #include<iostream> #in ...

  7. hdu 2167(状压dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2167 思路:经典的状压dp题,前后,上下,对角8个位置不能取,状态压缩枚举即可所有情况,递推关系是为d ...

  8. Engineer Assignment HDU - 6006 状压dp

    http://acm.split.hdu.edu.cn/showproblem.php?pid=6006 比赛的时候写了一个暴力,存暴力,过了,还46ms 那个暴力的思路是,预处理can[i][j]表 ...

  9. hdu 3254 (状压DP) Corn Fields

    poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两 ...

随机推荐

  1. javascript 迭代与递归

    <script type="text/javascript"> // //原生js // window.onload = function(){ // var btn ...

  2. HDU - 3521 An easy Problem(矩阵快速幂)

    http://acm.hdu.edu.cn/showproblem.php?pid=3521 题意 对于矩阵A,求e^A的值. 分析 这个定眼一看好像很熟悉,就是泰勒展开,可惜自己的高数已经还给老师了 ...

  3. Gym - 100269F Flight Boarding Optimization(dp+树状数组)

    原题链接 题意: 现在有n个人,s个位置和你可以划分长k个区域你可以把s个位置划分成k个区域,这样每个人坐下你的代价是该区域内,在你之前比你小的人的数量问你怎么划分这s个位置(当然,每个区域必须是连续 ...

  4. gcc和gdb使用笔记

    gcc: http://wiki.ubuntu.org.cn/Gcchowto gdb: http://wiki.ubuntu.org.cn/%E7%94%A8GDB%E8%B0%83%E8%AF%9 ...

  5. SpringMVC学习笔记_02

    1.springmvc对多视图的支持 (1)导入xml格式视图支持的jar包   注意:springmvc本身就支持xml格式,所以不用导入其他支持的jar包了. (2)在springmvc.xml中 ...

  6. python安装办法

    先我们来安装python 1.首先进入网站下载:点击打开链接(或自己输入网址https://www.python.org/downloads/),进入之后,选择64位下载. 2.下载完成后如下图所示 ...

  7. Qt之QEvent(所有事件的翻译)

    QEvent 类是所有事件类的基类,事件对象包含事件参数. Qt 的主事件循环(QCoreApplication::exec())从事件队列中获取本地窗口系统事件,将它们转化为 QEvents,然后将 ...

  8. comfirm和prompt的区别

    comfirm和prompt的区别. <html> <title>测试页面</title> <head> </head> <body& ...

  9. 洛谷4718【模板】Pollard-Rho算法

    传送门 Description: 给定T个数,分别求出它们的最大质因数 Solution: 其实大概框架是很容易想到的 对于一个数n 找到它的一个因数x 判断这个因数是不是质数 如果是质数就更新答案 ...

  10. vscode 配置Git

    步骤: 下载Git客户端 配置环境变量 设置vscode与Git的关联 重启 步骤一: 该网址,下载即可. https://git-scm.com/downloads 步骤二: 计算机 > 属性 ...