TrickGCD
URL: http://acm.hdu.edu.cn/showproblem.php?pid=6053
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
题解
莫比乌斯&容斥
ans=∑d=2n−μ(d)∏i=1n⌊ain⌋
转化一下
ans=∑d=2n−μ(d)∏i=1max(ai)nitimes(i,d)
其中
times(i,d)=∑⌊akd⌋=i1
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 5;
const int MOD = 1e9 + 7;
bool notp[MAXN];
int prime[MAXN], mu[MAXN], sz;
void init() {
for(int i = 2; i < MAXN ; ++i) {
if(!notp[i]) {
mu[i] = -1;
prime[sz++] = i;
}
for(int j = 0; j < sz; ++j) {
int t = i * prime[j];
if(t >= MAXN) break;
notp[t] = true;
if(i % prime[j]) {
mu[t] = -mu[i];
} else {
mu[t] = 0;
break;
}
}
}
}
int pow(int a, int n) {
int res = 1;
while(n) {
if(n&1) res = 1LL * res * a % MOD;
a = 1LL * a * a % MOD;
n >>= 1;
}
return res;
}
int dp[MAXN], num[MAXN], T, n, low, top;
void slove(int Case) {
int pos = 0, mul = 1, ans = 0;
for(int i = 2; i <= top; ++i) {
num[i] += num[i - 1];
}
for(int d = 2; d <= low; ++d) {
int res = -mu[d];
for(int i = 1; i <= top/d; ++i) {
res = 1LL * res * pow(i, num[min(i * d + d - 1, top)] - num[i * d - 1]) % MOD;
}
ans = (ans + res) % MOD;
}
printf("Case #%d: %d\n", Case, (ans + MOD) % MOD);
}
int main()
{
init();
/*
for(int i = 2; i < 20; ++i) {
printf("%-2d %d\n", i, mu[i]);
}
*/
scanf("%d", &T);
for(int Case = 1; Case <= T; ++Case) {
memset(num, 0, sizeof(num));
low = 1 << 30, top = 0;
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
int x;
scanf("%d", &x);
++num[x];
low = min(low, x);
top = max(top, x);
}
slove(Case);
}
return 0;
}