您的位置:首页 > 其它

【HDU 6053 TrickGCD】 + 莫比乌斯反演

2017-07-28 10:49 381 查看
TrickGCD

Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 1002 Accepted Submission(s): 389

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

Source

2017 Multi-University Training Contest - Team 2

题意 : b[i] 可以从 1 ~ a[i] 之间选个数,任意 gcd(b[l] ~ b[r]) > 1,可以有多少中 b 数组

思路 : 枚举每个因数 o,对于 b,可以选择的数有 o * 1,o * 2,o * 3…o * b / o,有 b / o 个,对整个数组来说 贡献所有 b / o 的乘积, 预处理一下 l ~ r 之间有多少数,可以算出 o * r ~ o * (r + 1) - 1 之间的数的贡献都为 r,快速幂一下,最后利用 莫比乌斯反演去重

莫比乌斯反演是数论中的重要内容,在许多情况下能够简化运算

我们需要找到f(n)与F(n)之间的关系。从和函数定义当中,我们可以知道:

F(1)=f(1)

F(2)=f(1)+f(2)

F(3)=f(1)+ f(3)

F(4)=f(1)+f(2)+f(4)

F(5)=f(1)+f(5)

F(6)=f(1)+f(2)+f(3)+f(6)

F(7)=f(1)+f(7)

F(8)=f(1)+f(2)+f(4)+f(8)

那么:

f(1)=F(1)

f(2)=F(2)-f(1)=F(2)-F(1)

f(3) =F(3)-F(1)

f(4)=F(4) -f(2)- f(1) =F(4)-F(2)

f(5) =F(5)-F(1)

f(6)=F(6)-F(3)-F(2)+F(1)

f(7)=F(7)-F(1)

f(8)=F(8)-F(4)

从中,可以看出,若n=p2(p为质数)那么,F(p)=f(1)+f(p),F(n)=f(1)+f(p)+f(p2),所以,f(n)=F(p2)-F(p)

AC代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 1e5 + 10;
const int mod = 1e9 + 7;
typedef long long LL;
LL sum[MAX],num[MAX];
LL km(LL a,LL b){
LL ans = 1;
while(b){
if(b & 1) ans = (ans * a) % mod;
b /= 2; a = (a * a) % mod;
}
return ans;
}
int main()
{
int T,nl = 0,n,x;
scanf("%d",&T);
while(T--){
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
scanf("%d",&n);
for(int i = 0; i < n; i++)
scanf("%d",&x),num[x]++;
for(int i = 2; i < MAX; i++) num[i] += num[i - 1];
LL ans = 0,cut = 0;
for(int i = 2; i < MAX; i++){
if(num[i - 1]) continue; // 有不满足的点
sum[i] = 1;
for(int j = i; j < MAX; j += i){
if(j + i >= MAX) cut = num[MAX - 1] - num[j - 1]; // j ~ MAX
else cut = num[j + i - 1] - num[j - 1];
if(!cut) continue;
sum[i] = (sum[i] * km(j / i,cut)) % mod;
}
}
for(int i = MAX - 1; i >= 2; i--)
for(int j = i + i; j < MAX; j += i)
sum[i] = (sum[i] - sum[j] + mod) % mod;
for(int i = 2; i < MAX; i++) ans = (ans + sum[i]) % mod;
printf("Case #%d: %lld\n",++nl,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  莫比乌斯反演