hdu 6053 TrickGCD [2017 Multi-University Training Contest

来源:互联网 发布:金字塔期货交易软件 编辑:程序博客网 时间:2024/05/24 05:39

点击打开题目

题意: 给你一个序列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;}/*12100000 100000Case #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;}


原创粉丝点击