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
題意:
你有一個數組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;
}