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,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两 ...
随机推荐
- 网络编程基础【day09】:解决socket粘包之大数据(七)
本节内容 概述 linux下运行效果 sleep解决粘包 服务端插入交互解决粘包问题 一.概述 刚刚我们在window的操作系统上,很完美的解决了,大数据量的数据传输出现的问题,但是在Linux环境下 ...
- Python基础【day03】:文件操作(七)
零.本节内容 1.文件常用操作汇总 2.打开文件 3.操作文件 4.关闭文件 一.文件常用操作汇总 二.打开文件 1.普通打开模式 r,英文:read,只读模式(默认) w,英文:write,只写模式 ...
- Dubbo的负载均衡
背景 Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容.一个服务通常会部署多个实例.如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略. 几 ...
- Neo4j安装&入门&一些优缺点
本篇将介绍Neo4j的安装,入门,和自己使用了一段时间后发现的优点缺点,争取简洁和实用. 如果你是第一次接触Neo4j,并且之前也都没接触过类似的Graph Database的话,建议先浏览一下我之前 ...
- jsp/servlet页面跳转丢失样式问题
问题:使用servlet,如何处理在多路径页面跳转中servlet转发页面样式丢失问题?(例如访问 http://localhost/project/listUser.action后转到http:// ...
- 下拉选择框QCombox
下拉列表框样式如图: 字体列表框样式: import sys from PyQt5.QtWidgets import QApplication, QWidget, QComboBox, QFontCo ...
- oracle锁表
一.锁表的处理 Oracle锁表比较简单,查询锁表的session杀掉就可以了. 1.以下几个为相关表 SELECT * FROM V$LOCK; SELECT * FROM V$SQLAREA; S ...
- 公共模块定义/草案(Common Module Definition / draft - CMD草案)
This specification addresses how modules should be written in order to be interoperable in browser-b ...
- Responsive响应式设计
在IE6-8中完全是不支持CSS3 Media Queries的.那么为了让IE6-8支持,我们就很有必要的在IE9以下的浏览器中加上media-queries.js或者respond.js脚本: & ...
- Linux组管理和权限管理
⒈Linux组基本介绍 1)在Linux中的每个用户必须属于一个组,不能独立于组外. 2)Linux中每个文件都有所有者.所在组.其它组的概念 ①所有者 一般(默认)为文件的创建者,谁创建了该文件,就 ...