TrickGCD
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2177 Accepted Submission(s): 842
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
* 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 containsn numbers describe each element of
A
You can assume that1≤n,Ai≤105
Each test case begins with an integer number n describe the size of array A .
Then a line contains
You can assume that
Output
For the
k
th 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
, 现在有一个数列
解题思路:
其实正常的思路就是想到枚举
gcd
值,然后计算结果,但是发现这个比较不好求,所以不可行。所以考虑
di
表示 gcd为
i
的倍数的有
现在考虑如何计算
di
,其实就是用到了分块,因为我们发现在
k∈[j∗i,(j+1)∗i−1]
区间中,
ki
的值都是一样的,根据这个原理,我们可以求这个区间中有多少个
i
,然后快速幂一下就可以了,当然这个东西先求一个前缀和
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;
const int MAXN = 1e5+15;
LL sum[MAXN], d[MAXN];
LL Pow(LL a, LL b){
LL ans = 1;
while(b){
if(b & 1) ans = ans * a % MOD;
b>>=1;
a = (a * a) % MOD;
}
return ans;
}
int main()
{
///freopen("in.txt","r", stdin);
int T; scanf("%d", &T);
for(int cas=1; cas<=T; cas++){
int n, x, cnt; scanf("%d", &n);
int mi = MAXN, ma = -1;
memset(sum, 0, sizeof sum);
for(int i=0; i<n; i++) scanf("%d", &x), mi = min(mi, x), ma = max(ma, x), sum[x]++;
for(int i=1; i<=ma; i++) sum[i] += sum[i-1];
for(int i=2; i<=ma; i++){
d[i] = 1;
for(int j=i+i; j<=ma; j+=i){
if(i+j-1 > ma) cnt = sum[ma] - sum[j-1];
else cnt = sum[i+j-1] - sum[j-1];
if(cnt == 0) continue;
d[i] = d[i] * Pow(j/i, cnt) % MOD;
}
}
LL ans = 0;
for(int i=mi; i>1; i--){//一定是从后往前计算
for(int j=i+i; j<=mi; j+=i) d[i] = (d[i] - d[j]) % MOD;
ans = (ans + d[i]) % MOD;
}
ans = (ans % MOD + MOD) % MOD;
printf("Case #%d: %lld\n",cas, ans);
}
return 0;
}