HDU 6053 TrickGCD(莫比乌斯反演)

来源:互联网 发布:网络建设服务商 编辑:程序博客网 时间:2024/06/04 23:32
TrickGCD

Problem Description

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


Source

2017 Multi-University Training Contest - Team 2


题意:给出长度为n的a数列,求满足条件的B数组的个数,条件:①1<=b[i]<=a[i] ②区间整体gcd>=2
题解:

令g(d)为gcd为d的倍数的答案


根据容斥原理,去掉重复的情况(如g(2)+g(3)-g(6))



f(i,d)表示序列a中a/d=i的元素个数,可以通过预处理出前缀和+快速幂,之后利用预处理出莫比乌斯函数后进行简单的反演即可算出答案,总复杂度nlogn^2


#include<iostream>#include<stdio.h>#include<string.h>#include<vector>#include<algorithm>#include<math.h>#include<queue>#define INF 1e9#define ll long long#define maxn 300005#include<set>#include<stack>using namespace std;int n,m,mm;int a[100005];int mo[100005];bool isprime[100005];int num[100005];ll mod=1e9+7;void mobi(){    memset(isprime,true,sizeof(isprime));    isprime[1]=false;    for(int i=2;i<100005;i++)        if(isprime[i])        {            mo[i]=-1;            for(int j=2;i*j<100005;j++)            {                if(j%i==0) mo[i*j]=0;                else mo[i*j]=-mo[j];                isprime[i*j]=false;            }        }}ll quickpow(ll n,ll m){    ll ans=1;    n%=mod;    while(m)    {        if(m%2==1)        {            ans=ans*n;            ans=ans%mod;            m=m-1;        }        else        {            n=(n*n)%mod;            n%=mod;            m=m/2;        }    }    return ans%mod;}int main(){    int t;    scanf("%d",&t);    mobi();    for(int w=1;w<=t;w++)    {        scanf("%d",&n);        m=0;        mm=100005;        memset(num,0,sizeof(num));        memset(a,0,sizeof(a));        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            m=max(a[i],m);            mm=min(mm,a[i]);            num[a[i]]++;        }        cout<<"Case #"<<w<<": ";        for(int i=1;i<=m;i++)            num[i]+=num[i-1];        ll ans=0;        for(int i=2;i<=mm;i++)        {            if(mo[i]==0) continue;            ll sum=1;            for(int j=1;j<=m/i;j++)            {                ll mi=1ll*(num[min(m,j*i+i-1)]-num[j*i-1]);                sum*=quickpow(1ll*j,mi);                sum%=mod;            }            ans+=sum*(-mo[i]);            ans=(ans+mod)%mod;        }        cout<<ans%mod<<endl;    }    return 0;}


原创粉丝点击