zoukankan      html  css  js  c++  java
  • codeforce 839d.winter is here

    题意:如果一个子序列的GCD为1,那么这个子序列的价值为0,否则子序列价值为子序列长度*子序列GCD

    给出n个数,求这n个数所有子序列的价值和

    题解:首先得想到去处理量比较少的数据的贡献,这里处理每个gcd的贡献。我们定义f(i)为gcd==i的倍数时的贡献,那么f(i)=c(0,n)*0+c(1,n)*1+...c(n,n)*n ,这里的n为能够整除i的数的个数。然后利用容斥把gcd==i的贡献筛出来(这里无非就是要把其倍数处理掉~)。

    然后结合c(1,n)+c(2,n)+....c(n,n)=2^n这个可以推出f(i)=n*2^(n-1)。然后倒着容斥一下(虽然自己看着别人的代码看了半天,这里还是装逼带过吧23333)。

    ac代码:

    #include<stdio.h>  
    #define mod 1000000007  
    #define LL long long  
    LL cnt[1000005], sum[1000005];  
    LL Pow(LL a, LL b)  
    {  
        LL now;  
        now = 1;  
        while(b)  
        {  
            if(b%2)  
                now = now*a%mod;  
            a = a*a%mod;  
            b /= 2;  
        }  
        return now;  
    }  
    int main(void)  
    {  
        LL ans, i, j, n, x;  
        scanf("%lld", &n);  
        for(i=1;i<=n;i++)  
        {  
            scanf("%lld", &x);  
            cnt[x]++;  
        }  
        ans = 0;  
        // 注意转换下题目意思 去枚举每个gcd的贡献
        for(i=1000000;i>=2;i--)  
        {  
            x = 0;  
            for(j=i;j<=1000000;j+=i)  
            {  
                sum[i] -= sum[j]; // 容斥 把倍数的结果去掉 
                x += cnt[j]; // 记录gcd为x的个数
            }  
            sum[i] += x*Pow(2, x-1)%mod;  //  这里的sum[i]为gcd==i的时候的贡献
            ans = ((ans+sum[i]*i)%mod+mod)%mod;  
        }  
        printf("%lld
    ", ans);  
        return 0;  
    }  
  • 相关阅读:
    linux指令之系统信息查看
    linux指令之文件创建删除查看复制剪切
    c++函数参数类型-引用、指针、值 [转载]
    C++笔记 --- 头文件一览[转载]
    #include< >和#include""的区别
    DeleteFile()参数
    C++文件流读写详解
    Visual Studio中的Build和Rebuild区别
    STL 容器
    Android复习资料
  • 原文地址:https://www.cnblogs.com/z1141000271/p/7419717.html
Copyright © 2011-2022 走看看