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

题目链接:hdu 6125 Free from square

题意:

从不大于n的所有正整数中选出至少1个且至多k个使得乘积不包含平方因子。

题解:

很容易想到,选出来的数所包含的每个质因子只能有一个。

那么我们对所有的质因子进行状压dp,500以内大概有100个质因子。

那么就成了2100,显然不能接受。

然后我们发现,对于每一个x(x<=n),x最多只包含一个大于sqrt(n)的质因子。

然后我们就可以将大于sqrt(n)的x按照x所包含的那个质因子分组。

比如 n=500,现在有53 54 55 56 57...114。那么53和106在一组,57和114在一组。(可能还有其他的组,这里我随便举例)

在同一组里每个数只能选一次,所以就是分组背包。

所以我们就可以将该问题拆成两个部分:

1.小于sqrt(n)的部分进行状压dp。

2.大于sqrt(n)的部分进行分组背包。

最后将所有合法的答案加起来就行了。(ps:注意处理1这个数字和过滤掉含有多个质因子的数)

 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 4 using namespace std;
 5 
 6 const int N=505,P=1e9+7,U=(1<<8)-1;
 7 int t,n,K;
 8 int p[8]={2,3,5,7,11,13,17,19};
 9 int dp[2][N][1<<8],st[N],cur;
10 vector<int>v[N],small;
11 
12 inline void up(int &a,int b){a+=b;if(a>P)a-=P;}
13 
14 void solve()
15 {
16     mst(dp,0),cur=0;
17     mst(st,0),small.clear();
18     F(i,1,n)v[i].clear();
19     F(i,1,n)
20     {
21         int flag=1,tmp=i;
22         F(j,0,7)
23         {
24             if(tmp%(p[j]*p[j])==0){flag=0;break;}
25             else if(tmp%p[j]==0)
26             {
27                 tmp/=p[j],st[i]|=1<<j;
28             }
29         }
30         if(tmp==1&&flag)small.push_back(i);
31         else if(flag)v[tmp].push_back(i);
32     }
33     dp[cur][0][0]=1,dp[cur][1][0]=1;//考虑1这个数
34     int sz=small.size();//先处理只含小因子的数
35     F(k,1,sz-1)F(i,0,K-1)F(j,0,U)if(dp[cur][i][j])
36     {
37         int x=small[k];
38         if(j&st[x])continue;
39         up(dp[cur][i+1][j|st[x]],dp[cur][i][j]);
40     }
41     F(i,1,n)//将含大因子的数进行分组背包
42     {
43         if(v[i].size()==0)continue;
44         cur^=1,memcpy(dp[cur],dp[cur^1],sizeof(dp[cur]));
45         F(j,0,K-1)F(k,0,U)if(dp[j][k])
46         {
47             for(auto &it:v[i])
48             {
49                 if(k&st[it])continue;
50                 up(dp[cur][j+1][k|st[it]],dp[cur^1][j][k]);
51             }
52         }
53     }
54     int ans=0;
55     F(i,1,K)F(j,0,U)up(ans,dp[cur][i][j]);
56     printf("%d\n",ans);
57 }
58 
59 int main(){
60     scanf("%d",&t);
61     while(t--)scanf("%d%d",&n,&K),solve();
62     return 0;
63 }
View Code

 

posted @ 2017-08-16 16:41  bin_gege  阅读(233)  评论(0编辑  收藏  举报