HDU 6053 TrickGCD

来源:互联网 发布:数据泄密 编辑:程序博客网 时间:2024/05/08 16:11

TrickGCD

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



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

* 1≤Bi≤Ai
* For each pair( l , r ) (1≤l≤r≤n) , gcd(bl,bl+1...br)≥2

Input
The first line is an integer T(1≤T≤10) 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 1≤n,Ai≤105

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
1
4
4 4 4 4


Sample Output
Case #1: 17


Source
2017 Multi-University Training Contest - Team 2
 

Recommend
liuyiding


题意:

你有一个数组A(1<=ai<=100000),请构造出符合以下条件的数组:

1.1<=bi<=ai

2.数组中的所有元素的gcd大于等于2

求有存在多少个这样的数组,对答案取模1e9+7

思路:

莫比乌斯反演的做法,已知形式:

首先我们只考虑gcd大于等于2一种情况,设:

注:这里的[x]表示对x向下取整。

之后我们利用莫比乌斯函数的性质对d的所有情况求和:

我们再进一步化简:

f(i,d)为[ai/d]=i的A数组中的元素个数。

我们为什么可以这样化简?

计算每个ai/d向下取整,需要O(n)的时间,可以知道x=(int)(ai/d),然后在[x*d,x*d+d-1]这一段的取值是一样的,都等于x,那么我可以反过来,统计ai在区间[x*d,x*d+d-1]内的个数为y,求x^y,对x进行枚举,累乘,复杂度就下来了。(来自wannafly群里dalao的原话)

上面求x^y需要用到快速幂。

思路来源:http://blog.csdn.net/qq_32570675/article/details/76212197

以下是莫比乌斯反演资料:

某QAQ的博客:http://blog.csdn.net/a1s4z5/article/details/51333840

不知名dalao的ppt:http://vfleaking.blog.uoj.ac/slide/87#/

贾鹏志线性筛:https://wenku.baidu.com/view/2d706761aa00b52acec7ca63.html

示例程序

/*Problem : 6053 ( TrickGCD )     Judge Status : AcceptedRunId : 21404646    Language : G++    Code Len : 1475 BCode Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta*/#include <cstdio>#include <cstring>#include <algorithm>#define LDQ 1000000007#define QAQ 0x3f3f3f3fusing namespace std;int mu[100001];void init(){    int i,i1;    memset(mu,0,sizeof(mu));    mu[1]=1;    for(i=1;100000>=i;i++)    {        for(i1=i+i;100000>=i1;i1=i1+i)        {            mu[i1]=mu[i1]-mu[i];        }    }}long long quick(long long x,int n){    long long t=x,ans=1;    while(n!=0)    {        if(n%2==1)        {            ans=(ans*t)%LDQ;        }        t=(t*t)%LDQ;        n=n/2;    }    return ans;}int main(){    int n,t,i,i1,i2,x,num[100001],minx,maxx;    long long temp,sum;    init();            //莫比乌斯函数    scanf("%d",&t);    for(i=1;t>=i;i++)    {        scanf("%d",&n);        memset(num,0,sizeof(num));        minx=QAQ;        maxx=-QAQ;        for(i1=1;n>=i1;i1++)        {            scanf("%d",&x);            num[x]++;            minx=min(minx,x);            maxx=max(maxx,x);        }        for(i1=1;maxx>=i1;i1++)        {            num[i1]=num[i1]+num[i1-1];        }        sum=0;        for(i1=2;minx>=i1;i1++)        {            temp=1;            for(i2=1;maxx>=i2*i1;i2++)            {                temp=(temp*quick(i2,num[min(maxx,i1*i2+i1-1)]-num[i1*i2-1]))%LDQ;            }            sum=(sum-mu[i1]*temp+LDQ)%LDQ;        }        printf("Case #%d: %lld\n",i,sum);    }    return 0;}