题目
题意
给一个数组 {Ai},求能得到多少种数列 {Bi}
{Bi} 需要满足:
1. 1 ≤ Bi ≤ Ai
2. 对于(l,r)( 1 ≤ l ≤ r ≤ n ),gcd(bl, bl+1 … br) >= 2
题解
这道题需要用到莫比乌斯反演的知识,如果不会可以先看一下
http://blog.csdn.net/acdreamers/article/details/8542292 这篇博文。
第二个条件其实就是 gcd(b1, b2 … bn) >= 2 ,然后可以根据下面这些公式得到最终解:
gcd(b1, (b2 … bn) >= 2) = (gcd ≥ 1) - (gcd = 1)
(gcd ≥ 1) = a1 * a2 * … * an
(gcd = 1) = ∑minAix=1µ(x)∏ni=1floor(Ai/x) ∑ x = 1 m i n A i µ ( x ) ∏ i = 1 n f l o o r ( A i / x )
但是这样的时间复杂度是 n2 ,还要用分块的方法优化一下,用 sum[i] 表示 Aj <= i 的总数,对于每个 x ,当 d 在 [i,i+d-1] 这样一区间内,x/d 的值是一样的。所以就可以用快速幂将这段累乘优化为 pow(x/d, (sum[i+d-1] - sum[i-1])) ,这样时间复杂度就变为 nlogn 。
代码
#include <algorithm>
#include <bitset>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
const int N = 100005;
int a[N],sum[N << 1];
bool check[N];
int prime[N];
int mu[N];
void Moblus() {
memset(check,false,sizeof(check)); mu[1] = 1;
int tot = 0;
for(int i = 2; i <= N; i++) {
if( !check[i] ) {
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot; j++) {
if(i * prime[j] > N)
break;
check[i * prime[j]] = true;
if( i % prime[j] == 0){
mu[i * prime[j]] = 0;
break;
}
else {
mu[i * prime[j]] = -mu[i];
}
}
}
}
const long long mod = 1000000007;
long long pow_mod(long long a,long long b){
long long ans = 1,base = a;
while(b){
if(b % 2)
ans = ans * base % mod;
base = base * base % mod;
b >>= 1;
}
return ans;
}
int main(){
int t;
cin >> t;
Moblus();
for(int cnt = 1;cnt <= t; ++cnt){
int n;
cin >> n;
memset(sum,0,sizeof(sum));
int mn = INT_MAX;
int mx = 0;
for(int i=1;i<=n;++i){
scanf("%d",a + i);
mn = min(a[i],mn);
mx = max(a[i],mx);
++sum[a[i]];
}
for(int i=2;i<=mx + mn;++i){
sum[i] += sum[i-1];
}
long long ans = 0;
for(int i=2;i<=mn;++i){
long long temp = 1;
if(mu[i] != 0){
for(int j=i;j<=mx;j+=i){
temp = (temp * pow_mod(j/i,sum[j+i-1] - sum[j-1])) % mod;
}
ans = (ans - mu[i] * temp + mod) % mod;
}
}
cout<<"Case #"<< cnt <<": "<<ans<<endl;
}
return 0;
}