1. 程式人生 > >【CF402D】Upgrading Array(素數+質因數+gcd+貪心)

【CF402D】Upgrading Array(素數+質因數+gcd+貪心)

不難發現 題目中給出的f函式 其實就是一個數分解質因數後好素數和壞素數的個數之差

也就是說 數x帶來的貢獻 與x的質因數的種類有關係 又聯想到gcd[1~x]一定是這個數的因子 也就是說一個數的貢獻可以表示成:f(gcd[1~x])+f(....)

容易想到貪心做法:我們從後往前列舉 如果當前gcd字首帶來的貢獻<0 就除一下

另外有幾個小細節我平時沒有注意到的:
1.線性篩素數 其實列舉範圍只需要到區間根號範圍就行 如果要用到特別大的那幾個素數只需特判就行(46行)
2.map和bitset屌爆了

#include<bits/stdc++.h> 
#define N 2000005
#define MAX 5000000
#define int long long
using namespace std;
template<class T>
inline void read(T &x)
{
    x=0;
    static char ch=getchar();
    while(ch<'0'||ch>'9')   ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
int n,m,a[N],gcd[N];
int prime[MAX+5],cnt,isprime[MAX+5];
bitset<1000000005> bad;
inline int calcgcd(int a,int b)
{
    return b? calcgcd(b,a%b):a;
}
void GetPrime()
{
    isprime[0]=isprime[1]=1;
    for(register int i=2;i<=MAX;i++)
    {
        if(!isprime[i]) prime[++cnt]=i;
        for(register int j=1;j<=cnt&&i*prime[j]<=MAX;j++)
        {
            isprime[i*prime[j]]=1;
            if(i%prime[j]==0)   break;
        }
    }
}
inline int calc(int x)
{
    if(x==1)    return 0;
    int sum=0;
    for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;i++)
    {
        while(x%prime[i]==0)
        {
            sum+=(bad[prime[i]]?-1:1);
            x/=prime[i];
        }
    }
    if(x!=1)    sum+=(bad[x]?-1:1);
    return sum; 
}
main()
{
    read(n); read(m); 
    for(int i=1;i<=n;i++)   read(a[i]),gcd[i]=calcgcd(a[i],gcd[i-1]);
    GetPrime();
    for(int i=1,x;i<=m;i++) read(x),bad[x]=true;
    int ans=0,tag=1;
    for(int i=1;i<=n;i++)   ans+=calc(a[i]);
    for(int i=n;i>=1;i--)
    {
        gcd[i]/=tag;
        int tmp=calc(gcd[i]);
        if(tmp<0)
        {
            ans-=tmp*i;
            tag*=gcd[i];
        }
    }
    cout<<ans<<endl;
    return 0;
}