HDU 6053 逆向思维 gcd

来源:互联网 发布:java web工作流开发 编辑:程序博客网 时间:2024/06/09 09:03

TrickGCD

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2731    Accepted Submission(s): 1027


Problem Description
You are given an array A , and Zhu wants to know there are how many different array B satisfy the following conditions?

1BiAi
* For each pair( l , r ) (1lrn) , gcd(bl,bl+1...br)2
 

Input
The first line is an integer T(1T10) describe the number of test cases.

Each test case begins with an integer number n describe the size of array A.

Then a line contains n numbers describe each element of A

You can assume that 1n,Ai105
 

Output
For the kth test case , first output "Case #k: " , then output an integer as answer in a single line . because the answer may be large , so you are only need to output answer mod 109+7
 

Sample Input
144 4 4 4
 

Sample Output
Case #1: 17
 

Source
2017 Multi-University Training Contest - Team 2
 
题意:给出一个数组A 要你求出数组B的种数,其中对B有一些要求 就是Bi < Ai 并且满足所有Bi 里的gcd 不为 1,就是不互质
思路 : 先求一个前缀和 把对于k来说比它小的数的数量统计起来,然后从最小的数开始去求以它为gcd时候的组合种数,由于两个不互质的数的组合种数有重复算的部分
于是我们采用莫比乌斯反演来对它进行容斥。
代码如下
#include<stdio.h>#include<string.h>#define ll long long#define mod 1000000007#define MAXN 200005#define INF 0xfffffffll mub[100005];void Mobius(){    mub[1] = 1;    for(int i = 1;i <= 100000;i++){        for(int j = i + i;j <= 100000;j += i){            mub[j] -= mub[i];        }    }}ll Pow(ll a,ll b){    ll ans = 1;    while(b){        if(b & 1){            ans *= a;            ans %= mod;        }        a *= a;        a %= mod;        b /= 2;    }    return ans;}ll a[MAXN],sum[MAXN],k,Min;int main(){    Mobius();    int n,t,Case = 1;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        memset(a,0,sizeof(a));        Min = INF;        for(int i = 1;i <= n;i++){            scanf("%lld",&k);            a[k]++;            Min = k < Min ? k : Min;        }        ll ans = 0;        sum[0] = 0;        for(int i = 1;i < 200000;i++){            sum[i] = sum[i - 1] + a[i];        }        for(int i = 2;i <=  Min;i++){            ll temp = 1;            for(int j = 1;j * i <= 100000;j++){                temp = (temp * Pow((ll)j,sum[i * j + i - 1] - sum[i * j - 1])) % mod;            }            ans = (ans - temp * mub[i] + mod) % mod;        }        printf("Case #%d: %lld\n",Case++,ans);    }    return 0;}


原创粉丝点击