http://codeforces.com/contest/403/problem/B

You have an array of positive integers a[1], a[2], ..., a[n] and a set of bad prime numbers b1, b2, ..., bm. The prime numbers that do not occur in the set b are considered good. The beauty of array a is the sum , where function f(s) is determined as follows:

  • f(1) = 0;
  • Let's assume that p is the minimum prime divisor of s. If p is a good prime, then , otherwise .

You are allowed to perform an arbitrary (probably zero) number of operations to improve array a. The operation of improvement is the following sequence of actions:

  • Choose some number r (1 ≤ r ≤ n) and calculate the value g = GCD(a[1], a[2], ..., a[r]).
  • Apply the assignments: , ..., .

What is the maximum beauty of the array you can get?

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 5000) showing how many numbers are in the array and how many bad prime numbers there are.

The second line contains n space-separated integers a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ 109) — array a. The third line contains m space-separated integers b1, b2, ..., bm (2 ≤ b1 < b2 < ... < bm ≤ 109) — the set of bad prime numbers.

Output

Print a single integer — the answer to the problem.

 

题意:给定一个n个数的序列,和m个丑素数,每个数的f()为这个数的美素数个数*1+丑素数个数*(-1)。

现允许执行若干次操作:选择r,把a[1]~a[r]全部除以gcd(a[1],a[2]...a[r])

求最大的Σ f()。

思路:可以先求出原始的f(),再考虑操作。

操作应该每次优先选尽量大的r,为什么这样呢?

这么理解,假如除a1~a5的gcd对答案的正贡献为10,负贡献为-7,合贡献为+3,这时不应该a1~a5安排掉,应该目光放长远一些,有可能a1~a10的正贡献为8,负贡献为-2,总贡献+6。然后约去gcd,发现a1~a5的正贡献为+2,负贡献为-5,不应该除a1~a5了。

故贪心策略:从右向左扫一遍,看除gcd(不算右面已经用过的因子)的贡献是不是为正,为正就采纳。

其实不从右向左扫一遍,而是暴力模拟多次操作,每次尽量区间长,也可以过。

注意:

①Q:刘汝佳的质因数分解为什么最后特判n>1?

   A:考虑任意数n,将其分解质因数为n=a*b*c*d*e...,考虑最大的两个质因数x和y,sqrt(n)>=sqrt(x*y),也就是说,sqrt(n)的位置至少是在x和y之间,这时筛到x和y之间,会留下一个最后一个质数y,特判一下。考虑上比x,y小的那些,sqrt(n)只会更大,也就是说最坏情况下最后留一个质数,一般情况下一个质数都不留。

②一个优化,相比每次sqrt(n)分解质因数,预先筛好素数的效率提升了10倍(700ms->70ms),只需要筛sqrt(1e9)内的素数,而不需要筛整个1e9范围,因为最多n的两个因数都等于sqrt(n),不会两个素数均大于sqrt(n)的情况出现,否则n就>1e9了。因此最多1个素数因子大于sqrt(n),用①的最后特判就处理掉了。

#include<bits/stdc++.h>
using namespace std;

int n,m,a[6000],ans,g[6000];
set<int> ugly;
vector<int> prime;
int tot;

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}

void get_prime()
{
	bool vis[100000];
	int M=sqrt(1e9+10);
	for(int i=2;i<=M;i++)if(!vis[i])
		for(int j=i*i;j<=M;j+=i)vis[j]=1;
	for(int i=2;i<=M;i++)if(!vis[i])prime.push_back(i);
	tot=prime.size();
}

int div(int n)
{
	int ret=0;
	for(int i=0;i<tot&&n>1;i++)if(n%prime[i]==0)
	{
		int num=0;
		while(n%prime[i]==0)
		{
			num++;
			n/=prime[i];
		}
		if(ugly.count(prime[i]))ret-=num;
		else ret+=num;
	}
	if(n>1)
		if(ugly.count(n))ret--;
		else ret++;
	return ret;
}

void solve()
{
	g[1]=a[1];
	for(int i=2;i<=n;i++)g[i]=gcd(g[i-1],a[i]);
	int calced=1;
	for(int i=n;i>=1;i--)
	{
		int num=div(g[i]/calced);
		if(num<0)
		{
			ans-=num*i;
			calced=g[i];
		}
	}
}

int main()
{
	//freopen("input.in","r",stdin);
	cin>>n>>m;
	int x;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=m;i++){scanf("%d",&x);ugly.insert(x);}
	get_prime();
	for(int i=1;i<=n;i++)ans+=div(a[i]);
	solve();
	printf("%d\n",ans);
	return 0;
}