[Codeforces Round #428 DIV2D (CF839D)] Winter is here

题意

给定一个数列 ai ,若子序列长度为 k ,最大公约数为gcd,定义子序列的权值为 kgcd[gcd>1] 。求所有子序列的权值和。
n2105,ai106 ,答案对 109+7 取模。

题解

考虑枚举 gcd 。设 cnt gcd 的倍数的 ai 的个数。
gcd 是一个质数时,那么这个 gcd 的贡献即为

gcd(1C1cnt+2C2cnt++cntCcntcnt)

由基础的组合数学知识得上式的结果为
gcd(cnt2cnt1)

gcd 不是一个质数时,上式计算的贡献显然多了,它计算多的贡献是
x|gcdx(cnt2cnt1)

如果直接枚举因子减去多出的贡献,复杂度 O(AA) 的,不能接受。
从小到大枚举 gcd ,再将当前 gcd 的倍数都减去当前答案,或者预处理出 GCD[gcd]=gcdx|gcdx ,类似埃拉托斯特尼筛法复杂度 O(AloglogA)

代码

/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template<typename TP>inline bool MI(TP&a,const TP&b){return a>b?a=b,true:false;}
template<typename TP>inline bool MA(TP&a,const TP&b){return a<b?a=b,true:false;}

#define  kN  200010LL
#define  mod  1000000007LL
#define  kA  1000010LL

inline void inc(int&a,const int&b) {a+=b;if(a>=mod)a-=mod;}
inline void dec(int&a,const int&b) {a-=b;if(a<0)a+=mod;}

int n, ans = 0, ma = 1;
int cnt[kA], pow_2[kN], gcd[kA];

int main() {
    int i, j, now;
    r(n);
    Rep (i,1,n) r(j), cnt[j] ++ , MA(ma,j);
    pow_2[0] = 1;
    Rep (i,1,n) pow_2[i] = pow_2[i-1], inc(pow_2[i],pow_2[i-1]);
    Rep (i,2,ma)
        for (gcd[i]+=i, j=i<<1; j <= ma; j += i) dec(gcd[j],gcd[i]);
    Rep (i,2,ma) {
        for (now=0, j=i; j <= ma; j += i)
            now += cnt[j];
        if (!now) continue;
        inc(ans,1LL*now*gcd[i]%mod*pow_2[now-1]%mod);
    }
    printf("%d\n", ans);
    END: getchar(), getchar();
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值