• 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 }
  • 相关阅读:
    样式
    样式表的类别、选择器和优先级
    随记
    框架
    表单元素
    HTLM内容容器标签和常用标签
    HTML5的意义、改变以及全局属性
    11月21日html基础
    感想 目标和展望
    C++结构体实例和类实例的初始化
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7387897.html
Copyright © 2020-2023  润新知