星星之火

[jzoj 4668] [NOIP2016提高A组模拟7.19] 腐败 解题报告(质数分类+慢速乘)

题目链接:

http://172.16.0.132/senior/#main/show/4668

题目:

题解:

考虑把A数组里的每个元素分解质因数,对于每个质因数开一个vector存一下包含这个质因数的元素对应的这个质因数的指数

我们可以枚举质因数分别处理。为什么时间复杂度是对的呢?因为对于任何一个元素质因数种类是不会很多的,而对于每个质因数我们仅考虑包含它的数而不是全部扫一遍,因而是对的

枚举质因数之后,我们得到它对应的指数序列。对于小于等于根号1e7的质因数,考虑把这个指数序列从小到大,对于某个位置与之前位置的贡献就是靠前位置的指数,因此我们不断累加前缀统计答案就好了;对于另外的质因数,可以发现包含它的指数序列只能是1,所以我们不需要排序可以直接得到答案(注意到要求计算的数列其实就是元素之间两两只算一次,但注意还需要算上和本身的gcd)

这个模数比较坑,直接乘取模的话会爆long long,因此我们采用慢速乘(不是类似快速幂的那种)

比如x*y,我们令inf=1e7

$a1=x \mod inf$

$a2=x/inf$

$b1=y \mod inf$

$b2=y/inf$

我们拆开来计算就是了,具体看代码

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;

const int N=4e4+15;
const ll mo=1e11+9;
const int M=1e6+15;
const ll inf=1e7+15;
int n,cnt;
int a[N],vis[inf];
ll p[N];
vector <int> pi[M];
inline int read()
{
    char ch=getchar();int s=0,f=1;
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
void div(int x)
{
    for (int i=2;i*i<=x;i++)
    {
        if (x%i) continue;
        if (!vis[i]) p[++cnt]=i,vis[i]=cnt;
        int s=0;
        while (x%i==0) x/=i,++s;
        pi[vis[i]].push_back(s);
    }   
    if (x>1) 
    {
        if (!vis[x]) p[++cnt]=x,vis[x]=cnt;
        pi[vis[x]].push_back(1);
    }
}
ll mul(ll x,ll y)
{
    ll a1=x%inf;
    ll a2=x/inf;
    ll b1=y%inf;
    ll b2=y/inf;
    ll re=0;
    re=(re+a2*inf%mo*b2%mo*inf%mo)%mo;
    re=(re+a2*inf%mo*b1%mo)%mo;
    re=(re+a1*inf%mo*b2%mo)%mo;
    re=(re+a1*b1%mo)%mo;
    return re;
}
ll qpow(ll x,ll y)
{
    ll re=1;
    for (;y;y>>=1,x=mul(x,x)) if (y&1) re=mul(re,x);
    return re;
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) a[i]=read(),div(a[i]);
    ll ans=1;
    for (int i=1;i<=cnt;i++)
    {
        if (1ll*p[i]*p[i]<=inf)
        {
            int pnt=pi[i].size();
            sort(pi[i].begin(),pi[i].end());
            ll s=0;
            for (int j=0;j<pnt;j++)
            {
                ans=mul(ans,qpow(p[i],s));
                s+=pi[i][j];
            }
        }
        else 
        {
            ll c=pi[i].size();
            ans=mul(ans,qpow(p[i],c*(c-1)/2));
        }
    }
    for (int i=1;i<=n;i++) ans=mul(ans,1ll*a[i]);
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-10-30 07:58  星星之火OIer  阅读(309)  评论(0编辑  收藏  举报