题意:
一些坏的素数b 一串数字a 每次操作可以使a中前r个数字除以它们的gcd 操作次数不限 这串数字a有个得分 得分为每个数字中好素数个数减去坏素数个数 问 如何使a得分最大
思路:
以为每次操作都是对前r个数字除以gcd 自然想到从前到后扫描一遍用dp维护gcd
为了更贴近这道题我打了素数表 dp维护gcd即维护gcd中有几个相应的素数(相当于把gcd素数分解)
很显然操作应该从后往前做 因为做了前面可能影响后面不能做了
所以贪心从后到前扫描 如果gcd中坏的素数比好的素数多就操作除掉否则留下
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 5010
#define PM 32010
#define oo 2147483647
int n,m,cnt,ans,fgood,fbad;
int a[M],good[M],bad[M],gcdgood[M],gcdbad[M],p[M*2],which[M*2],dp[M*2];
int flag[PM];
void get_prime()
{
int i,j;
for(i=2;i<PM;i++)
{
if(!flag[i]) p[cnt++]=i;
for(j=0;j<cnt&&p[j]*i<PM;j++)
{
flag[p[j]*i]=1;
if(i%p[j]==0) break;
}
}
}
int main()
{
int i,j,k;
get_prime();
//printf("%d\n",cnt);
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=m;i++)
{
scanf("%d",&j);
if(j>p[cnt-1])
{
p[cnt]=j;
which[cnt]=1;
cnt++;
}
else
{
k=lower_bound(p,p+cnt,j)-p;
which[k]=1;
}
}
for(i=0;i<cnt;i++) dp[i]=oo;
for(i=1;i<=n;i++)
{
for(j=0;j<cnt;j++)
{
for(k=0;a[i]%p[j]==0;k++,a[i]/=p[j]);
if(which[j])
{
bad[i]+=k;
dp[j]=min(dp[j],k);
gcdbad[i]+=dp[j];
}
else
{
good[i]+=k;
dp[j]=min(dp[j],k);
gcdgood[i]+=dp[j];
}
}
if(a[i]!=1) good[i]++;
}
for(i=n;i;i--)
{
good[i]-=fgood;
bad[i]-=fbad;
gcdgood[i]-=fgood;
gcdbad[i]-=fbad;
if(gcdbad[i]>=gcdgood[i])
{
good[i]-=gcdgood[i];
bad[i]-=gcdbad[i];
fgood+=gcdgood[i];
fbad+=gcdbad[i];
gcdgood[i]=0;
gcdbad[i]=0;
}
ans+=good[i]-bad[i];
}
printf("%d\n",ans);
return 0;
}