此题最大的坑点在数据范围,他不写到方框里面我还以为a[i],b[i]都在1e6,给我考场上爆成30分了
一道好题
首先我们观察f(s)的生成方式,容易看出这与线性筛的筛法有很多相似之处。再注意到输入中输入有许多坏素数,就容易想到线性筛了。
我们可以轻易地预处理出1e6范围内的素数,顺便处理出他们的f值
const int M = 1e6+10;
int not_prime[M],prime[M],f[M],pcnt=0;
void init_prime(){
for(re int i=2;i<=(M-9);++i){
if(!not_prime[i]) prime[++pcnt]=i,f[i]=isbad_prime[i]?-1:1;
for(re int j=1;j<=pcnt&&prime[j]*i<=(M-9);++j){
not_prime[prime[j]*i]=1,f[prime[j]*i]=f[i]+(isbad_prime[prime[j]]?-1:1);
if(!i%prime[j]) break;
}
}
}
推出 $a[i]>1e6$ 时 $f[a[i]]$ 的计算方式其实也是顺理成章
ll calc(ll x){
if(isbad_prime[x]) return -1;
if(x<M-9) return f[x];
for(int i=1;i<=pcnt&&prime[i]<=x;++i)
if(x%prime[i]==0)
return calc(x/prime[i])+(isbad_prime[prime[i]]?-1:1);
return 1;
}
至于最终的前缀GCD修改,其实只是看着唬人。考场上我看到带修改就先跳了这道,结果最后发现这道最简单。(然而仍然没有1A)考虑到由坏素数筛出的数中间一定有$f[t]=f[k]-1$这步过程,要$\sum_{i=1}^Nf[i]$最大,自然希望把GCD中的坏素数都修改掉。
我们就能得出贪心:
从后往前枚举前缀的公共gcd $g[i]$ ,当 $f[g[i]]<0$ 时,说明这个时候坏素数应该被筛掉了。这样依次进行……
数学证明等我有空再写
AC代码(又长又慢):
#include <bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;
inline int red(){
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int N = 2010;
const int K = 1e9+5;
const int M = 1e5+10;
int n,m;
int a[N],f[M];
int bad_prime[N],bcnt=0;
bitset <K> isbad_prime;
int not_prime[M],prime[M],pcnt=0;
void init_prime(){
for(re int i=2;i<=(M-9);++i){
if(!not_prime[i]) prime[++pcnt]=i,f[i]=isbad_prime[i]?-1:1;
for(re int j=1;j<=pcnt&&prime[j]*i<=(M-9);++j){
not_prime[prime[j]*i]=1,f[prime[j]*i]=f[i]+(isbad_prime[prime[j]]?-1:1);
if(!i%prime[j]) break;
}
}
}
ll g[N];
ll gcd(int a,int b){return b?gcd(b,a%b):a;}
void init_gcd(){
for(re int i=1;i<=n;++i) g[i]=gcd(a[i],g[i-1]);
}
ll calc(ll x){
if(isbad_prime[x]) return -1;
if(x<M-9) return f[x];
for(int i=1;i<=pcnt&&prime[i]<=x;++i)
if(x%prime[i]==0)
return calc(x/prime[i])+(isbad_prime[prime[i]]?-1:1);
return 1;
}
int main(){
n=red(),m=red();
for(re int i=1;i<=n;++i) a[i]=red();
for(re int i=1;i<=m;++i) bad_prime[++bcnt]=red(),isbad_prime[bad_prime[bcnt]]=1;
init_prime();
init_gcd();
ll ans=0,tag=1;
for(re int i=1;i<=n;++i) ans+=calc(a[i]);
for(re int i=n;i;--i){
g[i]/=tag;
ll tmp=calc(g[i]);
if(tmp<0) ans-=tmp*1LL*i,tag*=g[i];
}
printf("%lld",ans);
return 0;
}