题解 : 一开始理解错了题意思 还 naive 的以为只能操作一次,理解了题意以后,我们可以发现这个题目,后面的不会影响前面的,怎么说的,就是靠后的除以一个 gcd 如果前面还能除则不会对前面造成影响,这样的话就是一种逆序的思维,剩下的就可以贪心的做了。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <map>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int n,m;
ll a[maxn] = {0};
ll gc = 0;
map <ll,int> vis;
ll prime[maxn / 10] = {0};
map <ll,int> dp;
int cnt = 0;
void init () {
for (int i = 2;i < maxn; ++ i) {
if (!vis[i]) {
prime[cnt ++] = i;
for (int j = i + i;j < maxn; j += i) {
vis[j] = 1;
}
}
}
}
ll add = 0;
int pos = 0;
ll temp = 0;
ll g = 0;
void divide (ll n) {
ll tem = n;
temp = 0;
if (n <= 1) {
return ;
}
if (dp[n]) {
temp = dp[n];
return ;
}
for (int i = 0;i < cnt && prime[i] * prime[i] <= n; ++ i) {
while (tem % prime[i] == 0) {
if (vis[prime[i]]) {
temp --;
}
else temp ++;
tem /= prime[i];
}
}
if (tem != 1) {
if (vis[tem]) {
temp --;
}
else temp ++;
}
dp[n] = temp;
}
int main () {
ios_base :: sync_with_stdio(false);
init ();
vis.clear();
cin >> n >> m;
for (int i = 1;i <= n; ++ i) {
cin >> a[i];
}
for (int i = 0;i < m; ++ i) {
int x;
cin >> x;
vis[x] = 1;
}
ll ans = 0;
for (int i = 1;i <= n; ++ i) {
divide(a[i]);
ans += temp;
}
// int flag = 0;
for (ll i = n;i >= 1;-- i) {
g = a[i];
for (ll j = i;j >= 1; -- j) {
g = __gcd (g,a[j]);
}
divide(g);
// cout << temp << endl;
if (temp < 0) {
// flag = 1;
ans += (i * -temp);
for (int j = 1;j <= i; ++ j) a[j] /= g;
}
}
cout << ans << endl;
return 0;
}