HDU 6053 TrickGCD 线性筛 思维 容斥

来源:互联网 发布:网络主播沟通技巧 编辑:程序博客网 时间:2024/06/05 10:42

http://blog.csdn.net/wyg1997/article/details/76269665
港聚聚的博客 以及题目

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;typedef long long LL;const int mod = 1e9+7;const int N = 1e5;int dp[N+100];int a[N+100];int num[N+100];int n;LL qmod(LL a,LL b){    LL tmp = 1;    a%=mod;    while(b){        if (b&1) tmp = tmp*a%mod;        a = a*a%mod;        b>>=1;    }    return tmp;}int main(){    int t;    scanf("%d",&t);    int kase = 1;    while (t--){        int mn = 0x3f3f3f3f;        memset(dp,0,sizeof(dp));        memset(a,0,sizeof(a));        int ss;        scanf("%d",&n);        for (int i  = 0;i < n; ++i){            scanf("%d",&ss);            mn = min(mn,ss);            a[ss] ++;        }        /*处理每个数出现次数的前缀和*/        for (int i = 1; i <= 1e5; ++i){            num[i] = num[i-1]+a[i];        }        /*筛出所有因子的倍数 记录每个数所有倍数的个数(相乘算所有数gcd的全部组合种类数)*/        for (int i = 2;i <= 1e5; ++i){            if (i>mn){                dp[i] = 0;                continue;            }            dp[i] = 1;            for (int j = 0;j <= N; j+=i){                LL a,b;                a = j/i;                /*对区间求i的倍数的个数*/                if (j==0) b = 0;                else if (i+j-1>N) b = num[N]-num[j-1];                else b = num[i+j-1]-num[j-1];                dp[i] = dp[i]*qmod(a,b)%mod;            }        }        LL ans = 0;        /*每个数的倍数都是有重复的 所以算这个数的种类数时要去掉它的倍数的种数(去重)*/        /*比如样例 4 4 4 4 2的倍数有两个 总种类数为2^4 3的倍数只有它自己 且只出现一次 所以是 1 4的倍数有一个 总种类数是1 算2的时候减去1 算4只有1 所以一共是17*/        for (int i = N; i >= 2; --i){            for (int j = i+i; j <= N; j+=i){                dp[i] = (dp[i]-dp[j]+mod)%mod;            }            ans = ans+dp[i];            ans%=mod;        }        printf("Case #%d: %lld\n",kase++,ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击