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

HDU - 6125: Free from square (狀壓DP+分組背包)

素數 scanf style 多少 tor mod def c++ n)

problem:給定N,K。表示你有數1到N,讓你最多選擇K個數,問有多少種方案,使得選擇的數的乘積無平方因子數。N,K<500;

solution:顯然可以狀壓DP做,但是500以內的素數還是蠻多的,無法高效得DP。 但是我們註意到,大於sqer(N)的素數,同一類最多用一個,這不就是分組背包嗎。

所以我們只有小於sqrt(N)的素數用常規的DP,否則用分組背包。 dp[i][j]表示選擇了i個數,其中小於sqrt(N)的素數狀態為j。 j<(1<<8);

分組背包:我們把個數放在第一維,就保證了同一類的物品不相互影響,做到了分組。

#include<bits/stdc++.h>
#define
rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int Mod=1e9+7; const int maxn=510; int dp[maxn][256],a[maxn],x[maxn]; int p[]={2,3,5,7,11,13,17,19}; vector<int>G[maxn]; void init(int N) { rep(i,1,N) G[i].clear(); rep(i,1,N){ int t=i,tmp=0; rep(j,
0,7){ if(t%(p[j]*p[j])==0) { t=-1; break; } if(t%p[j]==0) { t/=p[j]; tmp|=(1<<j); } } if(t!=-1) { G[t].push_back(i); x[i]=tmp; } } }
int main() { int N,T,K,ans; scanf("%d",&T); while(T--){ memset(dp,0,sizeof(dp)); dp[0][0]=1; ans=0; scanf("%d%d",&N,&K); init(N); rep(j,0,G[1].size()-1) //1單獨考慮 for(int v=K-1;v>=0;v--){ int t=G[1][j]; rep(k,0,255){ if((x[t]&k)==0){ (dp[v+1][k|x[t]]+=dp[v][k])%=Mod; } } } rep(i,2,N){ if(G[i].size()==0) continue; for(int v=K-1;v>=0;v--) //放在第一維保證了分組 rep(j,0,G[i].size()-1){ int t=G[i][j]; rep(k,0,255){ if((x[t]&k)==0){ (dp[v+1][k|x[t]]+=dp[v][k])%=Mod; } } } } rep(j,1,K) rep(i,0,255) (ans+=dp[j][i])%=Mod; printf("%d\n",ans); } return 0; }

HDU - 6125: Free from square (狀壓DP+分組背包)