可以说是道半结论题了
开始想到了大半,但是没想全
首先可以发现前缀Gcd是单调不增的
那么也就是说
越后面的数的前缀gcd是肯定小于前面的数的
同时,前面的数的前缀gcd一定是后面的前缀gcd的倍数
那么也就是说我们只能从后面往前不断除gcd
因为除完这里这里的的前缀gcd就为1了
再除后面的就没有用了
我们还可以发现
每个数的“ f ” 也就是它的贡献
是其质因子中“好的”减去“坏的”
这个很好理解吧
因为它一定是由这些质因子转移过来的
然后我们就可以发现我们可以贪心处理
从后往前枚举当前的gcd的分数
如果小于0
也就是对答案有负的贡献
那我们就除去它
这样一定是正确的
考虑如果这里没有除去
那么在更前面的地方一定还是会除去
而且中间必定会有一部分负的贡献没有被除去
所以说我们只需要从后往前处理
预处理所以前缀gcd
如果gcd贡献为负
就直接暴力除去
#include<bits/stdc++.h>
#define ll int
using namespace std;
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res;
}
bool f;
ll ans;
int m,n,prime[100005],cnt,vis[100005],a[100005],pre[100005],zhi[1000005];
map<int,int> mp;
inline int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
inline void init(){
for(int i=2;i<=100005;i++){
if(!vis[i]){
prime[++cnt]=i;
for(int j=i+i;j<=100005;j+=i){
vis[j]=true;
}
}
}
}
inline int calc(int x){
int res=0;
for(int i=1;i<=cnt;i++){
while(x%prime[i]==0){
res+=(mp[prime[i]]?-1:1);
x/=prime[i];
}
}
if(x!=1){
res+=mp[x]?-1:1;
}
return res;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=m;i++)mp[read()]=1;
init();
for(int i=1;i<=n;i++)pre[i]=gcd(a[i],pre[i-1]);
for(int i=1;i<=n;i++)ans+=calc(a[i]);
int woc=1;
for(int i=n;i>=1;i--){
pre[i]/=woc;
int t=calc(pre[i]);
if(t<0){
ans-=t*i;
woc*=pre[i];
}
}
cout<<ans;
return 0;
}