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;
}