HDU 6053 莫比乌斯反演

来源:互联网 发布:jqueryrotate.js教程 编辑:程序博客网 时间:2024/05/21 22:43

题目

TrickGCD

题意

给一个数组 {Ai},求能得到多少种数列 {Bi}
{Bi} 需要满足:
1. 1 ≤ Bi ≤ Ai
2. 对于(l,r)( 1 ≤ l ≤ r ≤ n ),gcd(bl, bl+1 … br) >= 2

题解

这道题需要用到莫比乌斯反演的知识,如果不会可以先看一下
http://blog.csdn.net/acdreamers/article/details/8542292 这篇博文。

第二个条件其实就是 gcd(b1, b2 … bn) >= 2 ,然后可以根据下面这些公式得到最终解:

gcd(b1, (b2 … bn) >= 2) = (gcd ≥ 1) - (gcd = 1)

(gcd ≥ 1) = a1 * a2 * … * an

(gcd = 1) = minAix=1µ(x)ni=1floor(Ai/x)

但是这样的时间复杂度是 n2 ,还要用分块的方法优化一下,用 sum[i] 表示 Aj <= i 的总数,对于每个 x ,当 d 在 [i,i+d-1] 这样一区间内,x/d 的值是一样的。所以就可以用快速幂将这段累乘优化为 pow(x/d, (sum[i+d-1] - sum[i-1])) ,这样时间复杂度就变为 nlogn 。

代码

#include <algorithm>#include <bitset>#include <cstring>#include <cstdio>#include <cmath>#include <cstdlib>#include <climits>#include <iostream>#include <list>#include <map>#include <queue>#include <set>#include <stack>#include <string>#include <vector>using namespace std;const int N = 100005;int a[N],sum[N << 1];bool check[N];int prime[N];int mu[N];void Moblus() {    memset(check,false,sizeof(check)); mu[1] = 1;    int tot = 0;    for(int i = 2; i <= N; i++) {        if( !check[i] ) {            prime[tot++] = i;            mu[i] = -1;        }        for(int j = 0; j < tot; j++) {            if(i * prime[j] > N)                 break;             check[i * prime[j]] = true;            if( i % prime[j] == 0){                mu[i * prime[j]] = 0;                break;             }            else {                mu[i * prime[j]] = -mu[i];            }         }    }}const long long mod = 1000000007;long long pow_mod(long long a,long long b){    long long ans = 1,base = a;    while(b){        if(b % 2)            ans = ans * base % mod;        base = base * base % mod;        b >>= 1;    }    return ans;}int main(){    int t;    cin >> t;    Moblus();    for(int cnt = 1;cnt <= t; ++cnt){        int n;        cin >> n;        memset(sum,0,sizeof(sum));        int mn = INT_MAX;        int mx = 0;        for(int i=1;i<=n;++i){            scanf("%d",a + i);            mn = min(a[i],mn);            mx = max(a[i],mx);            ++sum[a[i]];        }        for(int i=2;i<=mx + mn;++i){            sum[i] += sum[i-1];        }        long long ans = 0;        for(int i=2;i<=mn;++i){            long long temp = 1;            if(mu[i] != 0){                for(int j=i;j<=mx;j+=i){                    temp = (temp * pow_mod(j/i,sum[j+i-1] - sum[j-1])) % mod;                }                ans = (ans - mu[i] * temp + mod) % mod;            }        }        cout<<"Case #"<< cnt <<": "<<ans<<endl;        }    return 0;}
原创粉丝点击