zoukankan      html  css  js  c++  java
  • 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
    ",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
  • 相关阅读:
    mysql存储过程基本函数
    Java多线程程序设计详细解析
    手把手教你写Undo、Redo程序
    mysql存储过程学习总结-操作符
    深入解析ATL第二版(ATL8.0)笔记--(2.3节)
    mysql 5.0存储过程学习总结
    php判断浏览器和语言
    Windows7系统环境安装配置PHP开发环境
    Nginx环境下Php安装
    php学习
  • 原文地址:https://www.cnblogs.com/bin-gege/p/7374156.html
Copyright © 2011-2022 走看看