HDU 6053 TrickGCD

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
 

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 : Accepted
RunId : 21404646    Language : G++    Code Len : 1475 B
Code Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LDQ 1000000007
#define QAQ 0x3f3f3f3f
using 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章