题意: 给你一个序列a,求满足对于所有l, r都有gcd(b[l], ... , b[r]) >= 2并且bi <= ai的b序列的数量.
分析: 先枚举gcd的值, 然后利用前缀和快速算出a[i]/g = c(c = 1, 2, 3, ...)的个数, 然后用快速幂, 快速算出gcd为g的时候的值, 最后用容斥筛选(或者用莫比乌斯函数).
代码1[容斥]:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<cmath>
typedef long long ll;
const int maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
using namespace std;
int a[maxn], sum[maxn];
ll dp[maxn];
ll qmod(ll x, ll y) {
ll ans = 1;
while(y) {
if(y & 1) ans = ans * x % mod;
x = x * x % mod;
y /= 2;
}
return ans;
}
int main() {
int n, t, x, v = 1;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
memset(a, 0, sizeof a);
memset(sum, 0, sizeof sum);
memset(dp, 0, sizeof dp);
for(int i = 0; i < n; i++) {
scanf("%d", &x);
a[x]++;
}
for(int i = 1; i < maxn; i++) {
sum[i] = sum[i - 1] + a[i];
}
ll a, b;
int j;
for(int i = 2; i <= 100000; i++) {
if(sum[i - 1] > 0) break;
dp[i] = 1;
for(j = i + i; j <= 100000; j += i) {
if(j + i > 100000) b = sum[100001] - sum[j - 1];
else b = sum[j + i - 1] - sum[j - 1];
a = j / i;
dp[i] = dp[i] * qmod(a, b) % mod;
}
}
for(int i = 100000; i >= 2; i--) {
for(int j = i + i; j <= 100000; j += i) {
dp[i] = (dp[i] - dp[j] + mod) % mod;
}
}
ll ans = 0;
for(int i = 2; i < maxn; i++) {
ans = (ans + dp[i]) % mod;
//if(dp[i]) printf("%d %lld\n", i, dp[i]);
}
printf("Case #%d: %lld\n", v++, ans);
}
return 0;
}
/*
1
2
100000 100000
Case #1: 920698472
*/
代码2[莫比乌斯函数]:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<cmath>
typedef long long ll;
const int maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
using namespace std;
int a[maxn], sum[maxn], mu[maxn];
ll dp[maxn];
void getmu() {
for(int i = 1; i <= maxn; i++) {
int t = i == 1 ? 1 : 0;
int d = t - mu[i];
mu[i] = d;
for(int j = i + i; j <= maxn; j += i) {
mu[j] += d;
}
}
}
ll qmod(ll x, ll y) {
ll ans = 1;
while(y) {
if(y & 1) ans = ans * x % mod;
x = x * x % mod;
y /= 2;
}
return ans;
}
int main() {
int n, t, x, v = 1;
memset(mu, 0, sizeof mu);
getmu();
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
memset(a, 0, sizeof a);
memset(sum, 0, sizeof sum);
memset(dp, 0, sizeof dp);
for(int i = 0; i < n; i++) {
scanf("%d", &x);
a[x]++;
}
for(int i = 1; i < maxn; i++) {
sum[i] = sum[i - 1] + a[i];
}
ll a, b;
int j;
for(int i = 2; i <= 100000; i++) {
if(sum[i - 1] > 0) break;
dp[i] = 1;
for(j = i + i; j <= 100000; j += i) {
if(j + i > 100000) b = sum[100001] - sum[j - 1];
else b = sum[j + i - 1] - sum[j - 1];
a = j / i;
dp[i] = dp[i] * qmod(a, b) % mod;
}
}
ll ans = 0;
for(int i = 2; i < maxn; i++) {
ans = (ans - mu[i] * dp[i] + mod) % mod;
}
printf("Case #%d: %lld\n", v++, ans);
}
return 0;
}