您的位置:首页 > 其它

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

2017-08-16 16:02 274 查看
题解:因为小于根号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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: