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
解法:显然所有的GCD不等于1的数,都可以用素数和素数的组合的倍数来表达,那么1e5的数据大概有10000个素数,这里计算多少个数的GCD等于某个素数的组合显然需要容斥,但是如果容斥的时候直接O(n)计算,显然是会TLE的。我们可以用经典的剪枝,当我们处理的数为x的时候我们会发现a[i]/x的值会分成一段段相等的值,这就让我们想到通过a[i]/x来把a[i]分成块来算,然后每一块的答案就是长度的2^len,每一块相乘就是为GCD为x的答案,套上容斥就可以过啦。当然计算这个也是可以Mobius的啦。补充:这里对于GCD为x的时候答案就是每一个a[i]/x的乘积,直接算是O(n)的。
复杂度:O(10000*log10000*sqrt(10000))
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+7;
const int mod = 1e9+7;
int n, a[maxn];
LL qsm(int a, int k){
LL res = 1, b = a;
while(k){
if(k&1) res=res*b%mod;
b=b*b%mod;
k>>=1;
}
return res;
}
int check(int k)
{
LL ret=1;
int t=1;
while((t+1)*k<a[1]) t++;
for(; t*k<=a[n]; t++){
int l=lower_bound(a+1,a+n+1,t*k)-a;
int r=lower_bound(a+1,a+n+1,(t+1)*k)-a;
ret *= qsm(t, r-l);
ret %= mod;
}
return ret;
}
int prime[maxn], tot;
LL ans;
bool isprime[maxn];
void init()
{
memset(isprime, true, sizeof(isprime));
for(int i=2; i<maxn; i++){
if(isprime[i]){
for(LL j=(LL)i*i; j<maxn; j+=i){
isprime[j]=false;
}
}
}
for(int i=2; i<maxn; i++){
if(isprime[i]){
prime[++tot]=i;
}
}
}
void dfs(int now, int k, int jud)
{
if(now > tot) return ;
LL temp = k*prime[now];
if(temp > a[1]) return;
dfs(now+1, k, jud);
ans = (ans + jud*check(temp)%mod + mod)%mod;
dfs(now+1, temp, -jud);
}
int main()
{
init();
int T,ks=0;
scanf("%d",&T);
while(T--)
{
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
sort(a+1, a+n+1);
ans=0;
dfs(1,1,1);
if(ans<0) ans+=mod;
printf("Case #%d: %lld\n", ++ks, ans);
}
return 0;
}