TrickGCD HDU

来源:互联网 发布:js控制标签显示隐藏 编辑:程序博客网 时间:2024/05/20 02:56

You are given an array AA , and Zhu wants to know there are how many different array BB 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 AA.

Then a line contains nn numbers describe each element of AA

You can assume that 1≤n,Ai≤1051≤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
这题之前做过,遇到一道类似的题,想来写个题解
这题有两种思想的解法,但是殊途同归,一个是容斥思想,另一个是莫比乌斯反演,先谈谈容斥,gcd要大于2,所以我们把bi里最小的数分解质因子,然后用状压枚举质因子组合,以前做过类似是求gcd要等于1的对数,做法是我们把所有gcd大于1的对数找出,然后总数减去。
看看莫比乌斯反演,我们能不能这样,把所有gcd等于1的对数找出,然后总数减去,设F(n)为gc为n的倍数的对数,
则:

F(x)=b1xb2x...bnx

f(x)为gcd等于x的个数,则
F(n)=n|df(d)

反演得:
f(n)=n|dμ(dn)F(d)

所以
f(1)=i=1+μ(i)F(i)

易知:total=b1b2...bn=F(1)
所以:
ans=totali=1+μ(i)F(i)

我们知道μ(1)=1
所以
ans=i=2+μ(i)F(i)

其实我用容斥做得到式子和这是一模一样的,其实容斥和莫比乌斯函数实质上是一样的(当然你可以用其他的方式实现容斥)

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<bitset>#include<vector>#define N 200005#define mod 1000000007using namespace std;typedef long long  ll;int mu[N];vector<int> prime;bool pri[N];void getM(){    memset(pri,true,sizeof(pri));    mu[1]=1;    for(int i=2;i<N;i++)    {        if(pri[i])        {            prime.push_back(i);            mu[i]=-1;        }        for(int j=0;j<prime.size()&&prime[j]*i<N;j++)        {            pri[prime[j]*i]=false;            if(i%prime[j])                mu[prime[j]*i]=-mu[i];            else            {                mu[prime[j]*i]=0;                break;            }        }    }}int num[N];ll P(ll a,ll b){    ll ans=1;    while(b)    {        if(b&1)            ans=ans*a%mod;        a=a*a%mod;        b>>=1;    }    return ans;}int main(){    getM();    int t;    int n;    scanf("%d",&t);    int x;    int cal=1;    while(t--)    {        scanf("%d",&n);        int minn=10000000;        int maxx=-1;        memset(num,0,sizeof(num));        for(int i=0;i<n;i++)        {            scanf("%d",&x);            minn=min(minn,x);            maxx=max(maxx,x);            num[x]++;        }        for(int i=100000;i>0;i--)            num[i-1]+=num[i];        long long ans=0;        //cout<<"min "<<minn<<endl;        for(int i=2;i<=minn;i++)        {            if(!mu[i])                continue;            ll temp=1;            ll now=1;            int p=i;            while(p<=maxx)            {                temp=temp*P(now++,num[p]-num[p+i])%mod;                p+=i;            }            ans=(-mu[i]*temp+ans+mod+mod)%mod;        }        printf("Case #%d: %lld\n",cal++,ans);    }    return 0;}
原创粉丝点击