题意
N个数A[i],可以给每个数除不超过K的因数,使得所有数GCD为1
代价是除的数个数 * 除的数的权值和
N <= 1e6 , A[i] <= 1e12
题解
**考虑所有数gcd的所有质因数,设D=P1a1P2a2 *…Pkak , 显然当次数为1的时候个数最大,这时最多只有11个质因数
把A[i]化简为只含D的质因数的向量,不同向量只有最多M = 12000个(注意这时A[i]肯定包含D,暴力打表的时候要注意)
并且最后最多对11个数操作。
对于211的状态分别记录能删除它的最优的11个数,这里用一个堆来处理,复杂度是(211 * 11 * M)
然后又两种方法,可以枚举11个数划分的集合数,然后连边跑最小权匹配
也可以记录每个数能更新的状态有哪些,然后枚举每个数更新DP(i,S)的值,DP表示选了i个数,覆盖集合为S。这个思想就像高维前缀和,保证每个数只在答案中贡献一次。这个复杂度是枚举子集O(311112)
复杂度显然不满,跑得还挺快
注意map的应用,权值相同并且简化后相同的多个数要用标号区分开。他们可以同时更新答案
总结:
关于GCD的题根据质因数个数很小状压的思想很常见,并且经常把每个质因数的次数看成一个向量,这样的向量通常很少,打个表看看。
最后集合大小很小,经常暴力枚举划分或者状压DP。
每个数只能更新一次,所以枚举每个数更新,注意计算复杂度的时候不是M * 2m,因为总共是枚举子集,是m*3m
用STL的时候要把细节理清楚,非常难调。
质因数分解的数组要开long long,GCD可能包含大质数
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll,ll> pr;
const ll inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 1000020;
const ll mod = 1e9 + 7;
namespace Prime{
const int N = 2e6;
int prime[N + 20],tag[N + 20],mn[N + 20],cnt;
void init (){
rep(i,2,N){
if ( !tag[i] ) prime[++cnt] = i;
rep(j,1,cnt){
if ( prime[j] * i > N ) break;
tag[i * prime[j]] = 1;
mn[i * prime[j]] = prime[j];
if ( i % prime[j] == 0 ) break;
}
}
}
}
using namespace Prime;
const int M = (1 << 11) + 10;
struct node{
int S;
ll mul[M];
vector <int> w;
}dt[12200];
int n,w[maxn],tot,tot2,S,val[maxn];
ll a[maxn],lim,d;
map <ll,int> vis;
map <pr,int> num;
vector <ll> vec;
vector <int> best[maxn];
ll gcd(ll a,ll b){
if ( !b ) return a;
return gcd(b,a % b);
}
void factor(ll n){
rep(i,1,cnt){
if ( (ll)prime[i] * prime[i] > n ) break;
if ( n % prime[i] == 0 ){
vec.pb(prime[i]);
while ( n % prime[i] == 0 ) n /= prime[i];
}
}
if ( n > 1 ) vec.pb(n);
sort(vec.begin(),vec.end());
S = (1 << vec.size()) - 1;
}
int sum[maxn];
void pre(){
init();
ll d = 0;
rep(i,1,n) d = gcd(d,a[i]);
if ( d == 1 ) return;
factor(d);
// rvc(i,vec) cout<<vec[i]<<endl;
rep(i,1,n){
ll cur = 1,x = a[i];
rvc(j,vec){
while ( x % vec[j] == 0 ) x /= vec[j] , cur *= vec[j];
// tmp.mul[1 << j] = cur , tmp.S |= 1 << j;
}
int &id = vis[cur];
if ( !id ){
id = ++tot;
x = a[i];
rvc(j,vec){
ll y = 1;
while ( x % vec[j] == 0 ) x /= vec[j] , y *= vec[j];
dt[tot].mul[1 << j] = y;
}
dt[tot].mul[0] = 1;
rep(j,1,S){
rep(k,0,vec.size() - 1){
if ( (j & (1 << k)) ){
dt[tot].mul[j] = dt[tot].mul[j ^ (1 << k)] * dt[tot].mul[1 << k];
break;
}
}
}
}
dt[id].w.pb(w[i]);
}
rep(i,1,tot){
sort(dt[i].w.begin(),dt[i].w.end()) , sum[i] = sum[i - 1] + dt[i].w.size();
// rvc(j,dt[i].w) cout<<dt[i].w[j]<<" ";
// cout<<dt[i].mul[S]<<endl;
}
priority_queue <pr> heap;
rep(k,1,S){
while ( heap.size() ) heap.pop();
rep(i,1,tot){
if ( dt[i].mul[k] <= lim ){ //当前数可以删除状态k
rvc(j,dt[i].w){
if ( heap.size() < vec.size() ) heap.push(mp(dt[i].w[j],sum[i - 1] + j));
else if ( heap.top().fi > dt[i].w[j] ){
heap.pop();
heap.push(mp(dt[i].w[j],sum[i - 1] + j)); //如果当前w相同,但是是不同数,要区分开
}
else break;
}
}
}
while ( heap.size() ){
pr cur = heap.top();
int &id = num[cur]; heap.pop();
if ( !id ) id = ++tot2 , val[tot2] = cur.fi;
best[id].pb(k);
}
}
}
ll f[15][M],g[15][M];
inline void up(ll &x,ll y){
if ( x == -1 ) x = y;
else x = min(x,y);
}
void solve(){
if ( !vec.size() ){
puts("0");
return;
}
/* rep(i,1,tot2){
cout<<val[i]<<endl;
rvc(j,best[i]) cout<<best[i][j]<<" ";
cout<<endl;
}*/
memset(f,-1,sizeof(f));
f[0][0] = 0;
rep(j,1,tot2){
memcpy(g,f,sizeof(f));
rvc(k,best[j]){
int s = best[j][k],s2 = S ^ s;
repd(i,vec.size() - 1,0){ //从大到小枚举,保证当前数只被选一次
for (register int l = s2 ; l ; l = (l - 1) & s2){
if ( g[i][l] == -1 ) continue;
up(f[i + 1][l | s],g[i][l] + val[j]);
}
up(f[i + 1][s],g[i][0] + val[j]);
}
}
}
ll ans = -1;
rep(i,1,vec.size()) if ( f[i][S] != -1 ) up(ans,f[i][S] * i);
cout<<ans<<endl;
}
int main(){
freopen("input.txt","r",stdin);
cin>>n>>lim;
rep(i,1,n) scanf("%lld",&a[i]);
rep(i,1,n) scanf("%d",&w[i]);
pre();
solve();
}