1. 程式人生 > >【2018/10/27測試T1】洛陽懷

【2018/10/27測試T1】洛陽懷

【題目】

傳送門

【分析】

其實這道題似乎沒有想象中的那麼難

先說一下如何求 f(x)f(x) 吧,對 xx 分解質因數,在這些質因數中,f(x)f(x) 就是好質數個數減去壞質數個數

因為按照題目中的式子,每次會除掉最小質因子,而產生的貢獻也取決於最小質因子是否為好質數,這樣不斷除下去之後就會發現把所有的質因子都算了一遍,也就是上面的式子

現在就考慮如何除區間 gcdgcd

比較顯然的是不能從前往後除,因為前面除了之後 gcdgcd 就恆為 11 了,就不能據需更新了

所以我們從後往前來掃,如果發現在當前的 gcdgcd 中,壞質數個數大於好質數個數(也就是分數為負數),就說明若除掉這個 g

cdgcd 會減少更多的壞數,就會更優一點,那就除掉

還有就是一個神奇東西 bitsetbitset,可以存下 10910^9 的資料,把它當成 $bool $ 型用就行了

【程式碼】

#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 5005
#define Max 50005
using namespace std;
int n,m,sum;
bitset<1000000005>Map;
int a[N],Gcd[N],prime[Max]; bool mark[Max]; void linear_sieves() { int i,j,up=sqrt(1e9); memset(mark,true,sizeof(mark)); mark[0]=mark[1]=false; for(i=2;i<=up;++i) { if(mark[i]) prime[++sum]=i; for(j=1;j<=sum&&i*prime[j]<=up;++j) { mark[i*prime[j]]=false; if(i%prime[
j]==0) break; } } } int divide(int x) { int i,ans=0; for(i=1;i<=sum&&prime[i]*prime[i]<=x;++i) { while(x%prime[i]==0) { x/=prime[i]; Map[prime[i]]?ans--:ans++; } } if(x>1) Map[x]?ans--:ans++; return ans; } int main() { // freopen("cup.in","r",stdin); // freopen("cup.out","w",stdout); int x,i,ans=0; linear_sieves(); scanf("%d%d",&n,&m); scanf("%d",&a[1]),Gcd[1]=a[1]; for(i=2;i<=n;++i) scanf("%d",&a[i]),Gcd[i]=__gcd(Gcd[i-1],a[i]); for(i=1;i<=m;++i) scanf("%d",&x),Map[x]=true; for(i=1;i<=n;++i) ans+=divide(a[i]); int div=1; for(i=n;i>=1;--i) { Gcd[i]/=div; if(Gcd[i]==1) continue; int num=divide(Gcd[i]); if(num<0) { ans+=i*(-num); div*=Gcd[i]; } } printf("%d",ans); // fclose(stdin); // fclose(stdout); return 0; }