hdu6125-(状态压缩+分组背包)

来源:互联网 发布:网站幻灯片js代码 编辑:程序博客网 时间:2024/05/18 02:11

题解:因为小于根号500的质数有8个,我们可以用二进制表示为放入的这些数已经含有前面8个质数的哪几个然后,因为选择1-k个数后相乘起来没有平方因子,所以有任何能除以这前面8个质数的平方的都不可以,还有就是如果这个数把这8个质数能取余等0的都除后等于1的话那么这个数应该在自己这个数这一组,如果不能等于1的话应该再除以后剩下的那一组,为什么呢?因为除以后就剩下它的结果很显然只剩下一个质数了,那么这些数不能同出现,所以分到同一组里面,如果等于1的话这些数可能同时出现,也可能不同时出现,但是可以用二进制表现出来,最后用二维dp来做那么转移方程就是:

if((k&d)==0) dp[j+1][k|d] = (dp[j+1][k|d]+dp[j][k])%mod;(j表示放了j个数,k,d用二进制表示含有前面8个质数的哪几个)            

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cstdio>#include<vector>using namespace std;typedef long long int ll;const ll mod = 1e9+7;const int mx = 505;int st[mx],belong[mx];ll dp[mx][mx];vector<int>v[mx];int p[] = {2,3,5,7,11,13,17,19};ll work(int n,int m){    memset(dp,0,sizeof(dp));    dp[0][0] = 1;    for(int i = 1; i <= n; i++)        v[i].clear(),belong[i] = i,st[i] = 0;    for(int i = 1; i <= n; i++)        for(int j = 0; j < 8; j++)            if(st[i]!=-1&&i%p[j] == 0&&i%(p[j]*p[j])!=0)                st[i] |= 1<<j,belong[i]/=p[j];            else if(i%(p[j]*p[j])==0){                st[i] = -1;                break;            }    for(int i = 1; i <= n; i++)        if(st[i]!=-1){            if(belong[i]==1) v[i].push_back(i);            else v[belong[i]].push_back(i);        }    for(int i = 1; i <= n; i++){        if(st[i]==-1||v[i].size()==0)            continue;        for(int j = m-1; j >= 0; j--)            for(int k = 0; k < (1<<8); k++)                for(int l = 0; l < v[i].size(); l++){                    int d = st[v[i][l]];                    if((k&d)==0)                        dp[j+1][k|d] = (dp[j+1][k|d]+dp[j][k])%mod;                }    }    ll ans = 0;    for(int i = 1; i <= m; i++)        for(int j = 0; j <(1<<8); j++)            ans = (ans+dp[i][j])%mod;    return ans%mod;}int main(){    int n,m;    int t;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        printf("%I64d\n",work(n,m));    }    return 0;}


原创粉丝点击