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

Posted 谦谦君子,陌上其华

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

以上是关于HDU 6125 Free from square(状态压缩+分组背包)的主要内容,如果未能解决你的问题,请参考以下文章

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

hdu 6125 Free from square (状压DP+分组背包)

SQFREE - Square-free integers

hdu 1518 Square

CF1497E2 Square-free division (hard version)

CF1497E1 Square-free division (easy version)