题意:给出1000个数,和一个整数10^12。求个数最少,和最小的子集,使得他们的乘积是时k的倍数。
题解:注意到k的约束的个数不是很大,然后dp[i][d]=dp[i][d/gcd(a[i],d])]+1;注意到只有k的约束的才有意义,然后就是离散化,然后dp,细节比较多,请查看代码。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL,LL> pLL; /* 1.离散化 2.dp */ #define N 1001000 vector<pLL> primeDiviser; vector<vector<int> > aiConPi; vector<int> mul; int init(vector<LL> a,int n,LL k){ //vector<bool> isPrim(N,true); for(LL i=2;i*i<=k;i++){ //if(!isPrim[i]) continue; // for(LL j=i*i;j<N;j++){ // isPrim[j] = false; // } if(k%i==0){ pLL tmpPrimeDiviser = make_pair(i,0); while(k%i==0){ tmpPrimeDiviser.second++; k/=i; } primeDiviser.push_back(tmpPrimeDiviser); } } if(k!=1){ primeDiviser.push_back(make_pair(k,1)); } //每个数包含的k的约数的个数 aiConPi = vector<vector<int> > (n,vector<int>(primeDiviser.size(),0)); for(int i=0;i<n;i++){ for(int j=0;j<(int)primeDiviser.size();j++){ while(a[i]%primeDiviser[j].first==0){ aiConPi[i][j]++; a[i]/=primeDiviser[j].first; } } } //离散化用的 mul = vector<int>(primeDiviser.size(),0); mul[primeDiviser.size()-1] = 1; for(int i=primeDiviser.size()-2;i>=0;i--){ mul[i] = mul[i+1]*(primeDiviser[i+1].second+1); } int ret = 0; for(int i=primeDiviser.size()-1;i>=0;i--){ ret += primeDiviser[i].second*mul[i]; } return ret; //最终的状态 目标状态 //target status的状态是 } const LL INF = (LL)1e18; int main(){ int n; LL k; while(cin>>n>>k){ vector<LL> a(n); for(int i=0;i<n;i++){ cin>>a[i]; } if(k==1){//没有素因子 LL ret = 0; for(int i=1;i<n;i++){ if(a[ret]>a[i]){ ret = i; } } cout<<1<<endl<<ret+1<<endl; continue; } int target = init(a,n,k);//找出全部素因子 //cout<<"target:"<<target<<endl; vector<vector<pLL> > dp(n+1,vector<pLL>(target+1,make_pair(INF,0))); vector<vector<int> > prev(n+1,vector<int>(target+1,-1)); dp[0][0]=make_pair(0,0);// // for(int i=0;i<n;i++){ // for(int j=0;j<(int)primeDiviser.size();j++){ // cout<<aiConPi[i][j]<<" "; // } // cout<<endl; // } // for(int i=0;i<(int)primeDiviser.size();i++){ // cout<<mul[i]<<" "; // } // cout<<endl; for(int i=1;i<=n;i++){ for(int j=0;j<=target;j++){ dp[i][j] = dp[i-1][j]; prev[i][j] = j; int last=0,cur=j; for(int e=0;e<(int)primeDiviser.size();e++){ last += mul[e] * max(0,cur/mul[e]-aiConPi[i-1][e]); cur%=mul[e]; } // cout<<"dp["<<i-1<<"]["<<last<<"]->"<<"dp["<<i<<"]["<<j<<"]"<<endl; if(dp[i][j] > make_pair(dp[i-1][last].first+1,dp[i-1][last].second+a[i-1])){ dp[i][j] = make_pair(dp[i-1][last].first+1,dp[i-1][last].second+a[i-1]); prev[i][j] = last; //cout<<j<<","<<last<<endl; } // cout<<"dp["<<i<<"]["<<j<<"]:"<<dp[i][j].first<<","<<dp[i][j].second<<endl; } } //cout<<"get here"<<endl; if(dp[n][target] == (pLL) make_pair(INF,0)){ cout<<"-1"<<endl; }else{ cout<<dp[n][target].first<<endl; for(int i=n,j=target;i>=1&&j!=0;j = prev[i][j],i--){ if(prev[i][j]==j){ continue; }else{ cout<<i<<" "; } // cout<<j<<endl; } cout<<endl; } } } /* 2 1 1000000000000 999999999999 */