ACM-ICPC 2018 沈阳赛区网络预赛 G.Spare Tire (容斥)

 

ai

 

题意:给出a的递推式,1到n中与m互质的数为i,求a[i]的和

思路:得到a的通项公式为n^2+n,Sn的通项为n*(n+1)*(2n+1)/6+n*(n+1)/2,与m不互质的数,是取m的素因子的乘积,那么将m分解质因数,通过容斥原理,就可以得到与m不互质的数,总和减去这些数对应的a的和就是答案了。在求这些不互质数对应a的总和的时候,如果一个一个求会超时,需要直接求和。比如存在一个素因子是k,那么需要求下标为k,2k,3k,4k……的a的和,即求(kn)^2+kn通项的求和,为k^2*n*(n+1)*(2n+1)/6+k*n*(n+1)/2,项数为n/k。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
ll prime[10100];
int pl=0;
bool vis[10100];
ll n,m;
void getprime()
{
    for(ll i=2;i<10010;i++)
    {
        if(vis[i]==false)
        {
            prime[++pl]=i;
        }
        for(int j=1;j<=pl&&i*prime[j]<10010;j++)
        {
            vis[i*prime[j]]=true;
            if(i%prime[j]==0)
            break;
        }
    }
}
ll num[15];
int tot;
void bre(ll n)//对n分解质因数
{
    tot=0;
    for(int i=1;i<=pl&&prime[i]*prime[i]<=n;i++)
    {
        if(n%prime[i]==0)
        {
            num[tot++]=prime[i];
            while(n%prime[i]==0)
            {
                n/=prime[i];
            }
        }
        if(n==1)
        break;
    }
    if(n!=1)
    {
        num[tot++]=n;
    }
}
ll inv2,inv3,inv6;
ll fpow(ll a,ll b)//快速幂
{
    ll ans=1;
    ll tmp=a%mod;
    while(b)
    {
        if(b&1)
        ans=ans*tmp%mod;
        tmp=tmp*tmp%mod;
        b>>=1;
    }
    return ans;
}
void solve()//用二进制实现容斥原理
{
    ll ans=0;
    for(int i=0;i<(1<<tot);i++)//容斥定理所有的关系最多为2^tot
    {
        int cnt=0;
        ll sum=1;
        for(int j=0;j<tot;j++)//循环prime中的每一个运算
        {
            if(i&(1<<j))//要掌握&运算,与i的二进制的第j位比较,看是否为1,是则选中
            {
                cnt++;//记录prime中的每个元素
                sum*=num[j];
            }
        }
        ll k=n/sum;
        sum%=mod;
        ll p=(1+k)*k%mod*inv2%mod*sum%mod;
        ll q=k*(k+1)%mod*(2*k+1)%mod*inv6%mod*sum%mod*sum%mod;
        if(cnt&1)
        {
            ans-=p;
            if(ans<0)
                ans+=mod;
            ans-=q;
            if(ans<0)
                ans+=mod;
        }
        else
        {
            ans=(ans+p);
            if(ans>mod)
                ans-=mod;
            ans+=q;
            if(ans>mod)
                ans-=mod;
        }
    }
    printf("%lld\n",ans);
            

}
int main()
{
    getprime();
    inv2=fpow(2,mod-2);
    inv6=fpow(6,mod-2);
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        bre(m);
        solve();
    }
}

 

posted @ 2018-09-11 20:19  Somnus、M  阅读(201)  评论(0编辑  收藏  举报