1. 程式人生 > >HDU 6125 Free from square(狀態壓縮+分組背包)

HDU 6125 Free from square(狀態壓縮+分組背包)

ear prim tac names %d pro ble 狀態 nbsp

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 }

HDU 6125 Free from square(狀態壓縮+分組背包)