ACM-ICPC 2018 瀋陽賽區網絡預賽 G Spare Tire(容斥)

https://nanti.jisuanke.com/t/31448c++

題意

 已知a序列,給你一個n和m求小於n與m互質的數做爲a序列的下標的和ui

分析

 打表發現ai=i*(i+1)。spa

易得前n項和爲 Sn=n*(n+1)(2*n+1)/6+n*(n+1)/2;咱們直接求與m互質的數較難,因此咱們能夠換個思路,求與 m不互質的數,那麼與m不互質的數,是取m的素因子的乘積(由於根據惟一分解定理,任意個數均可看做的素數積),那麼咱們將m分解質因數,經過容斥定理,就能夠得道與m不互質的數,總和sum減去這些數對應的a的和就是答案了。code

容斥原理的具體以下:xml

          區間中與i不互質的個數 = (區間中i的每一個質因數的倍數個數)-(區間中i的每兩個質因數乘積的倍數)+(區間中i的每3個質因數的成績的倍數個數)-(區間中i的每4個質因數的乘積)+...blog

         好比存在一個素因子是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;
typedef long long ll;
const int maxn  = 1e4 + 10;
const int mod = 1e9 + 7;
ll inv6=166666668;
ll inv2=500000004;
ll a[maxn];
ll cal(ll n,ll x){
    n/=x;
    return (n*(n+1)%mod*(2*n+1)%mod*inv6%mod*x%mod*x%mod+n*(n+1)%mod*inv2%mod*x%mod)%mod;
}
int main(){
    ll n,m;
    while(~scanf("%lld%lld",&n,&m)){
        ll tot = cal(n,1);
        int cnt=0;
        for(ll i=2;i*i<=m;i++){
            if(m%i==0){
                a[cnt++]=i;
                while(m%i==0) m/=i;
            }
        }
        if(m!=1) a[cnt++]=m;
        ll res=0;
        for(int i=1;i<(1<<cnt);i++){
            ll tmp=1;
            for(int j=0;j<cnt;j++){
                if((1<<j)&i){
                    tmp=tmp*a[j]%mod;
                }
            }
            tmp=cal(n,tmp);
            if(__builtin_popcount(i)&1) res=(res+tmp)%mod;
            else res=(res-tmp+mod)%mod;
        }
        printf("%lld\n",(tot-res+mod)%mod);
    }
    return 0;
}
相關文章
相關標籤/搜索