Hdu-6053 TrickGCD(莫比乌斯函数)

来源:互联网 发布:大数据修炼系统txt 编辑:程序博客网 时间:2024/06/04 19:26

You are given an array A, and Zhu wants to know there are how many different array B satisfy the following conditions? 

1BiAi  
* For each pair( l , r ) (1lrn   ) , gcd(bl,bl+1...br)2


You can assume that 1n,Ai105


分析:限制等价于gcd(1,n) >= 2,那么我们考虑分别计算gcd是2的倍数,gcd是3的倍数...gcd是k的倍数..然后相加,这样当然会有重复,所以我们只要在系数上乘上一个莫比乌斯函数就可以了,但是这样暴力枚举gcd后还要计算ai/k,还是n^2的,我们注意到n/k的取值随着k增大而减小,而且sum(n/k)是n*logn级别的,所以我们考虑直接枚举ai/k的解,然后事先对所有ai的值求一个前缀和,这样直接枚举ai/k的解j就可以了.


#include <bits/stdc++.h>#define N 100005#define INF 1000000007#define MOD 1000000007using namespace std;typedef long long ll;bool vis[N];int t,prime[N],cnt,n,Time,mu[N],a[N],f[N];ll ans;void init_mu(){    memset(vis,0,sizeof(vis));    mu[1] = 1;    cnt = 0;    for(int i = 2;i < N;i++)    {        if(!vis[i])        {            prime[cnt++] = i;            mu[i] = -1;        }        for(int j = 0;j < cnt && i*prime[j] < N;j++)        {            vis[i*prime[j]] = 1;            if(i % prime[j]) mu[i*prime[j]] = -mu[i];            else             {                mu[i*prime[j]] = 0;                break;            }        }    }}ll ksm(ll x,ll y){    ll ans = 1;    while(y)    {        if(y & 1) ans = ans * x % MOD;        x = x * x % MOD;        y >>= 1;    }    return ans;}int main(){    init_mu();    scanf("%d",&t);    while(t--)    {        ans = 0;        memset(f,0,sizeof(f));        scanf("%d",&n);        int Min = INF;        for(int i = 1;i <= n;i++)         {            scanf("%d",&a[i]);            Min = min(a[i],Min);            f[a[i]]++;        }        for(int i = 1;i < N;i++) f[i] += f[i-1];        for(int i = 2;i <= Min;i++)        {            ll temp = 1;            for(int j = i;j < N;j += i) temp = temp * ksm(j/i,f[min(j+i-1,N-1)] - f[j-1]) % MOD;            ans = (ans + temp*mu[i]*-1 + MOD) % MOD;        }          cout<<"Case #"<<++Time<<": "<<ans<<endl;    }}

原创粉丝点击