HDU 6125 Free from square (状压DP+分组背包)
题目大意:让你在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+分组背包)的更多相关文章
- HDU 6125 Free from square (状压DP+背包)
题意:问你从 1 - n 至多选 m 个数使得他们的乘积不能整除完全平方数. 析:首先不能整除完全平方数,那么选的数肯定不能是完全平方数,然后选择的数也不能相同的质因子. 对于1-500有的质因子至多 ...
- HDU 6125 Free from square 状态压缩DP + 分组背包
Free from square Problem Description There is a set including all positive integers that are not mor ...
- NOI 2015 寿司晚宴 (状压DP+分组背包)
题目大意:两个人从2~n中随意取几个数(不取也算作一种方案),被一个人取过的数不能被另一个人再取.两个人合法的取法是,其中一个人取的任何数必须与另一个人取的每一个数都互质,求所有合法的方案数 (数据范 ...
- 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 6125 Free from square(状态压缩+分组背包)
http://acm.hdu.edu.cn/showproblem.php?pid=6125 题意: 在${1,2,3,...n}$的数中选择1~k个数,使得它们的乘积不能被平方数整除(1除外),计算 ...
- 树形DP和状压DP和背包DP
树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...
- HDU 6149 Valley Numer II 状压DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意:中文题目 解法:状压DP,dp[i][j]代表前i个低点,当前高点状态为j的方案数,然后枚 ...
- HDU 5434 Peace small elephant 状压dp+矩阵快速幂
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: ...
随机推荐
- 微信小程序:获取地理定位和显示相应的城市名称。
最近在看微信小程序,遇到地理定位显示城市名称的问题.本文就是记录这一过程. 解决方案 ...
- nlogn求逆序对&&陌上花开
前置: nlogn逆序对: 前一个小时我还真的不会这个Orz 这里运用归并排序的思想. 对于一个序列,我们把它先分开,再合并成一个有序序列. 引自https://blog.csdn.net/qq_30 ...
- 我的第一个arcgis地图应用
步骤: 1.设置一个基本的html文档 <!DOCTYPE html> <html> <head> <meta http-equiv="Conten ...
- PHP学习总结(2)——PHP入门篇之PHP代码标识
认识PHP代码标识 想在页面中编写PHP代码非常容易,如下面代码: <?php echo "想学习php吗?来慕课网吧";?> 就像你可以编写JavaScript脚本 ...
- selenium+java启动chrome浏览器
- (0)资料官网【从零开始学Spring Boot】
Spring Boot官网:http://projects.spring.io/spring-boot/ Eclipse官网:http://www.eclipse.org/ Maven官网:http: ...
- 俄罗斯方块c/c++语言代码
/*******************************/ /******Writer: GJ *******/ /******Language: C *******/ /******Date ...
- php RSA 简单实现
这是rsa_private_key.pem-----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC ...
- telnet允许root用户登录
默认情况下,linux不允许root用户以telnet方式登录linux主机,若要允许root用户登录,可采取以下3种方法之一: 1.修改login文件 redhat中对于远程登录的限制体现在/ ...
- [React Router] Create a ProtectedRoute Component in React Router (setState callback to force update)
In this lesson we'll create a protected route just for logged in users. We'll combine a Route with a ...