zoukankan      html  css  js  c++  java
  • HDU 6125 Free from square (状压DP+分组背包)

     题目大意:让你在1~n中选择不多于k个数(n,k<=500),保证它们的乘积不能被平方数整除。求选择的方案数

    因为质数的平方在500以内的只有8个,所以我们考虑状压

    先找出在n以内所有平方数小于等于n的质数,然后我们把它们作为状压的状态

    然后要对每个小于n数进行状压,如果它不能被它能被质数的平方整除,那就筛出它所有的在状态内的质因子,大于状态内的质因子我们存到剩余因子的乘积的部分里

    比如46,它的状态可以表示成0000 0001 (19,17,13,11,7,5,3,2)  46/2=23,把它存到23的0000 0001状态里

    这么做之后,你会惊奇的发现,每个数字只被存到了一个地方,且只被存了一次!

    而这也是分组背包可行的关键

    下一步就是分组背包了

    我们从1遍历到n,遍历所有状态,如果存了,意味着这个状态表示的数可以选一个,就++

    然后枚举上一层进行转移即可

    细节可以看代码

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <vector>
      5 #define N 100
      6 #define M 505
      7 #define maxn (1<<8)+5
      8 #define ll long long 
      9 #define mod 1000000007
     10 using namespace std;
     11 
     12 int T,n,m,cnt,K;
     13 ll f[2][M][maxn],tmp[M][maxn];
     14 int p[M],ok[M],pr[M],can[M][maxn],use[M];
     15 int a[]={0,2,3,5,7,11,13,17,19,5000};
     16 vector<int>to[M];
     17 void clr()
     18 {
     19     for(int i=0;i<M;i++) to[i].clear();
     20     memset(p,0,sizeof(p));
     21     memset(ok,0,sizeof(ok));
     22     memset(pr,0,sizeof(pr));
     23     memset(can,0,sizeof(can));
     24     memset(use,0,sizeof(use));
     25     memset(f,0,sizeof(f));
     26     cnt=0;
     27 }
     28 void get_P()
     29 {
     30     for(int i=2;i<=n;i++)
     31     {
     32         if(!use[i]) pr[cnt++]=i;
     33         for(int j=0;j<cnt&&i*pr[j]<=n;j++){
     34             use[i*pr[j]]=1;
     35             if(i%pr[j]==0) break;}
     36     }
     37     for(int i=1;i<=n;i++)
     38     {
     39         int x=i,ps=0;
     40         for(int j=0;j<min(K,8);j++)
     41             if(x%(pr[j]*pr[j])==0) {
     42                 ok[i]=-1,p[i]=0;
     43                 break;
     44             }else if(ok[i]!=-1&&x%pr[j]==0)
     45             {
     46                 p[i]|=(1<<j);
     47                 x/=pr[j];
     48             } 
     49         if(ok[i]!=-1)
     50         {
     51             if(x!=1) to[x].push_back(i);
     52             else     to[i].push_back(i);
     53         } 
     54     }
     55     for(int i=1;i<=n;i++) //can数组表示i是否存了能用某个二进制质因子表示的数
     56     {
     57         if(ok[i]==-1) continue;
     58         for(int j=0;j<to[i].size();j++)
     59             can[i][p[to[i][j]]]=1;
     60     }
     61 }
     62 
     63 int main()
     64 {
     65     //freopen("aa.in","r",stdin);
     66     scanf("%d",&T);
     67     while(T--)
     68     {
     69         scanf("%d%d",&n,&m);
     70         clr();
     71         K=0;
     72         while(K+1<=8&&a[K+1]*a[K+1]<=n) K++;
     73         get_P();
     74         int y=1,x=0;
     75         for(int i=1;i<=n;i++){ //分组背包
     76             if(!to[i].size()) continue;
     77             for(int s1=0;s1<(1<<K);s1++)
     78                 for(int j=1;j<=m;j++)
     79                     f[y][j][s1]=f[x][j][s1];
     80             for(int s1=0;s1<(1<<K);s1++) 
     81             {
     82                 if(!can[i][s1]) continue;
     83                 f[y][1][s1]=(f[y][1][s1]+1)%mod; 
     84             //如果i的状态里有s1,那么说明这个状态表示的数可以直接被选,就++
     85                 for(int j=1;j<=m;j++)
     86                     for(int s2=0;s2<(1<<K);s2++)
     87                     {
     88                         if(s1&s2) continue;
     89                         f[y][j][s1|s2]+=f[x][j-1][s2];
     90                         f[y][j][s1|s2]%=mod;
     91                     }
     92             }
     93             swap(y,x);
     94         }    
     95         ll ans=0;  
     96         for(int s=0;s<(1<<K);s++)
     97             for(int j=1;j<=m;j++)
     98                 ans=(ans+f[x][j][s])%mod;
     99         printf("%lld\n",ans);
    100     }
    101     return 0;
    102 }
  • 相关阅读:
    linux+apache+nginx实现,反向代理动静分离
    apache编译安装php后需要注意以下配置
    nginx的gzip压缩功能
    linux+nginx+mysql+php环境下,安装ecshop
    LeetCode 328:奇偶链表 Odd Even Linked List
    LeetCode 160: 相交链表 Intersection of Two Linked Lists
    LeetCode 203:移除链表元素 Remove LinkedList Elements
    LeetCode 142:环形链表 II Linked List Cycle II
    LeetCode 141:环形链表 Linked List Cycle
    围观微博网友发起的美胸比赛学习爬取微博评论内容
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9696982.html
Copyright © 2011-2022 走看看