HDU 6125 Free from square(状态压缩+分组背包)

http://acm.hdu.edu.cn/showproblem.php?pid=6125

题意:

在${1,2,3,...n}$的数中选择1~k个数,使得它们的乘积不能被平方数整除(1除外),计算有多少种取法。

思路:

考虑一下他们的质因子,如果两个数有相同的质因子,那么它们两个肯定是不能同时选的。这是不是很像分组背包,但是如果以质因子来分类的话,一个数就可能处于多个背包当中,这样就不行了,因为一个数你只能在一个背包中。

这题的数据范围很小,在500的范围内,质数的平方数小于500的就8个数,${2,3,5,7,11,13,17,19}$,那我们就可以二进制压缩来记录每个数的质因子情况,当然了,大于19的质因子每个数最多只会有一个。这样的话到最后就能很方便的划分背包了。

最后分组背包求解。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,ll> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn=500+5;
17 const int mod=1e9+7;
18
19 int n, k;
20 int prime[]={2,3,5,7,11,13,17,19};
21 int st[maxn];
22 int dp[maxn][maxn];
23 int leave[maxn];
24 vector<int> v[maxn];
25
26 void solve()
27 {
28     memset(st,0,sizeof(st));
29     for(int i=1;i<=n;i++)  leave[i]=i;
30     for(int i=1;i<=n;i++)
31     {
32         for(int j=0;j<8;j++)
33         {
34             if(st[i]==-1)  break;
35             if(i%prime[j]==0 && i%(prime[j]*prime[j])!=0)
36                 st[i]|=1<<j, leave[i]/=prime[j];
37             else if(i%(prime[j]*prime[j])==0)
38                 st[i]=-1;
39         }
40     }
41     for(int i=1;i<=n;i++)  v[i].clear();
42     for(int i=1;i<=n;i++)
43     {
44         if(st[i]==-1)  continue;
45         if(leave[i]==1)  v[i].push_back(i);
46         else v[leave[i]].push_back(i);
47     }
48     memset(dp,0,sizeof(dp));
49     dp[0][0]=1;
50     for(int i=1;i<=n;i++)
51     {
52         if(st[i]==-1 || v[i].size()==0)  continue;
53         for(int j=k-1;j>=0;j--)
54         {
55             for(int s=0;s<(1<<8);s++)
56             for(int t=0;t<v[i].size();t++)
57             {
58                 int id=v[i][t];
59                 if((s&st[id])==0)
60                     dp[j+1][s|st[id]]=(dp[j+1][s|st[id]]+dp[j][s])%mod;
61             }
62         }
63     }
64
65     ll ans=0;
66     for(int i=1;i<=k;i++)
67     {
68         for(int s=0;s<(1<<8);s++)
69             ans=(ans+dp[i][s])%mod;
70     }
71     cout<<ans<<endl;
72 }
73
74 int main()
75 {
76     //freopen("in.txt","r",stdin);
77     int T;
78     scanf("%d",&T);
79     while(T--)
80     {
81         scanf("%d%d",&n,&k);
82         solve();
83     }
84     return 0;
85 }
时间: 2024-10-23 19:18:13

HDU 6125 Free from square(状态压缩+分组背包)的相关文章

POJ2923 状态压缩01背包 xingxing在努力

这道题算是很经典的状态压缩01背包了, 题意是有一个人要用两辆小汽车搬家, 每辆小汽车都有一个最大载重量, 现在有一些要搬的家具, 告诉你这些家具的重量, 问最少几次能将这些家具搬完(每次两辆汽车必须出动, 即使有一辆车什么都没有装)? 物品个数不超过10,根据经验一般有10存在的话都要带点暴力的色彩, 那么这道题就是先要预处理所有一次搬走的家具的集合, 然后就将其转化成了01背包的问假设d[i][j]是前i个家具中搬走了j(集合)家具所需要的最少次数那么d[i][j] = min(d[i-1]

hdu 4778 Gems Fight!(状态压缩+博弈+记忆化)

Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 1383    Accepted Submission(s): 587 Problem Description Alice and Bob are playing "Gems Fight!": There are Gems of G differe

Wireless Password - HDU 2825(ac自动机+状态压缩)

题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码. 1->, 所有的密码都是有小写字母组成. 2->,密码的长度是 n (1<= n <=25). 3->,密码至少包含 k 种字符集里面的单词. 比如,给集合{"she", "he"},单词长度是3,最少包含两个单词的密码,很明显只能是“she”(题目表述的不清楚).   分析:因为要统计记录到达每个点时候

HDU 1712 ACboy needs your help(分组背包)

题意:给你n的课程组,每个课程组有m个课程,每个课程有一个完成时间与价值.问在m天内每组课程组最多选择一个,这样可以得到的最大价值是多少 题解:分组背包,其实就是每个课程组进行01背包,再在课程组内部进行枚举课程,但是这儿必须将枚举课程放在最里层才能保证最多选择一个 #include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vec

HDU - 1712 - ACboy needs your help 【分组背包】

<题目链接> 题目大意:有n个课程,现在花M天来学习这些课程,学习每个课程花的天数所得到的价值不同,求M天怎么分配学习才能得到的价值最大.(这些课程得到的价值和所花天数的关系由矩阵给出) 解题分析:这是一个很明显的分组背包问题,将某一门课程花m个不同天数能够得到不同的价值看成是m个有各自花费和价值的物品,然后,又因为根据题意,每一门课程都只能选择一种花费的天数,于是,这道题就被很自然的转化为分组背包问题. #include <iostream> #include <algor

hdu Swipe Bo(bfs+状态压缩)错了多次的题

Swipe Bo Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1549    Accepted Submission(s): 315 Problem Description "Swipe Bo" is a puzzle game that requires foresight and skill. The main cha

hdu 3681 Prison Break (状态压缩+bfs+最短路)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3214    Accepted Submission(s): 829 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

HDU 1074 Doing Homework (状态压缩DP)

Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3595    Accepted Submission(s): 1424 Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lo

HDU 5094 --Maze【BFS &amp;&amp; 状态压缩】

Maze Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Submission(s): 903    Accepted Submission(s): 316 Problem Description This story happened on the background of Star Trek. Spock, the deputy captain of St